home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
pascal
/
bbskt30a.zip
/
BBSKIT.DOC
next >
Wrap
Text File
|
1993-11-10
|
196KB
|
5,107 lines
BBSkit
Version 3.0
Communications Toolkit
for Turbo Pascal 6.0
by Steve Madsen
Copyright
BBSkit, associated utilities, source code, and documentation are
copyright (c) 1991-93 by Steven Madsen. All rights reserved. No
part of this publication may be reproduced, stored in a retrieval
system, or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording or otherwise, without the
prior written permission of the author. No patent liability is
assumed with respect to the use of the information contained
herein. While every precaution has been taken in the preparation
of this manual, the author assumes no responsibility for errors
or omissions.
Other brand and product names are trademarks or registered
trademarks of their respective holders.
License Agreement
THIS SOFTWARE IS PROVIDED TO YOU SUBJECT TO THE TERMS AND
CONDITIONS OF THIS AGREEMENT. IN THE EVENT THAT YOU CANNOT
ACCEPT THESE TERMS AND CONDITIONS, YOU MUST DESTROY THIS SOFTWARE
WITH ALL DOCUMENTATION, INCLUDING THIS AGREEMENT, WITHIN 30 DAYS.
YOU MUST ALSO DESTROY ANY ADDITIONAL COPIES YOU HAVE MADE FOR
ARCHIVAL PURPOSES.
BBSKIT IS DISTRIBUTED AS SHAREWARE, WHICH MEANS YOU ARE GRANTED
A 30 DAY LIMITED LICENSE IN WHICH TO TRY THE TOOLKIT OUT AND
DECIDE IF IT IS SOMETHING YOU WILL CONTINUE TO USE. PAST THIS
30 DAY LICENSE, YOU ARE EXPECTED TO REGISTER THE TOOLKIT, OR
DESTROY ALL COPIES YOU HAVE MADE.
THE AUTHOR, STEVEN MADSEN, IS NOT RESPONSIBLE FOR ANY DAMAGES
WHICH OCCUR THROUGH THE USE OF BBSKIT OR ANY OF ITS ASSOCIATED
UTILITIES. BY USING THIS TOOLKIT, YOU HAVE ACCEPTED
RESPONSIBILITY FOR YOUR ACTIONS AND ANYTHING WHICH COMES OF THOSE
ACTIONS, INCLUDING DAMAGES TO HARDWARE THAT YOU OWN. USE THIS
SOFTWARE AT YOUR OWN RISK.
Chapter 1: Introduction to BBSkit
About this manual
Welcome to BBSkit 3.0! Thank you for supporting the
shareware concept in registering this package. I hope you will
find that BBSkit is the most powerful, easy to use toolkit
available for interfacing to a serial port for your Turbo Pascal
applications. Many long hours of hard work have gone into making
BBSkit a well-written and well-documented package, and I hope
your learning curve is a short one.
If you have never used objects before, please take the time
to read the first few chapters of this manual. They will provide
some useful hints on what you're getting yourself into when
combining telecommunications and the mysteries of the object
oriented paradigm.
The following tools were used to create BBSkit and the
documentation:
* Borland Pascal v7.0 from Borland International
* Turbo Assembler v3.2 from Borland International
* Microsoft Word for Windows v2.0c
Style conventions
This manual will make use of some style conventions
throughout the text which you should be aware of. Some of this
text is merely for information, while other text may mean serious
trouble for certain situations.
Indented text shows something that will appear on your
screen, example program text, or text your should type
into your computer.
The purpose of BBSkit
Ever since I became involved with telecommunications in the
mid 1980's, I have been very interested in writing applications
that work with the serial port. Particularly, I like writing
bulletin board systems. The only problem was that I found no
communications packages that met my standards, which included
being usable under Turbo Pascal. Thus, BBSkit was born.
My main idea in creating BBSkit was to provide the most
seamless environment for a BBS author to create his or her
application. BBS and door applications are complex things,
requiring a level of attention to detail that might not
immediately leap to mind. BBSkit takes most of the hassle of
coding the menial parts of a BBS or door and provides it in a
much easier to use object environment.
Think of BBSkit as a shell program. Everything you need to
use your modem or communicate through your serial port is already
there. You can route input and output, send and receive files,
and emulate over 10 different terminals. Now you can concentrate
on writing your application, not on communicating with your
serial port.
What's new in version 3.0?
Just as version 2.0 of BBSkit was a tremendous improvement
over 1.0, version 3.0 will add lots of new features you'll wonder
how you got along without! Concurrent port support has been
added. Now BBSkit makes it possible to write a two (or more)
line bulletin board that runs off of a single CPU. To make
concurrent port support easier to use, BBSkit has been changed to
use virtual consoles (VCs), which act just like your text screen.
Now each time you create a new object from the one provided with
BBSkit, it brings a VC with it. Anything that object wants to
write to the screen goes to the VC, and only gets displayed when
you want to see that console. Otherwise it happily works in the
background. How does BBSkit allow multiple nodes? It integrates
a public domain unit called MTASK, which gives TP programs the
ability to multithread, or have multiple threads of processing
running at the same time. BBSkit has been prepared to
automatically switch among these threads, giving the illusion of
multitasking to your BBSkit applications. The primary advantage
is that your single line systems can have a remote user on at the
same time that you can use the system _ no more waiting for a
user to get off just to use your BBS! Best of all, this
functionality comes without the overhead of a dedicated
multitasking system such as Windows or DESQview.
Some users of BBSkit 2.0 have asked about the possibility of
adding either RIP or NAPLPS to an upcoming version of BBSkit. I
am aware of these graphical protocols, and am considering the
possibility of adding them in the future. For now, however, BSP
will remain as the only graphics/mouse protocol in BBSkit. It
will most likely see some work in the future, but that's another
story...
Finally, Internet users will be very happy to hear about the
addition of a mailing list and ftp site just for BBSkit. See
appendix B for more information.
Thanks to...
I'd like to take this time to thank some people who have
helped bring version 3.0 to life with their own contributions of
bug reports, encouragement, praise and the occasional smack to
the head when I wasn't thinking:
Alain Abdul Sater
James Farley
Scott Hunt
Dave Nims
Caj Rosenqvist
James Still
Thanks, everyone, for supporting me in the last year. This
toolkit has evolved far more than I thought possible. When you
crank out your next killer BBS or door, drop me a note so I can
check out your work!
Chapter 2: Telecommunications 101
What exactly is telecommunications?
Telecommunications can mean different things, but in the
computer world is generally means connecting to another computer
by using your computer and modem. Telecommunications always
starts with someone dialing someone else up over the phone lines
for a specific purpose. This purpose might be to download a
file, send a message to a friend, play a game, or even read stock
quotes on an information service.
To the casual user, telecommunications probably seems pretty
simple, but in reality the programmer has a lot of information to
deal with, and a lot of little things to take care of, all while
dutifully serving the users needs and desires.
The hardware
Every IBM PC and compatible that has a serial port is based
on some version of the National 8250 UART. The 8250 will handle
the basic functions of serial input and output: sending and
receiving characters, keeping track of the status of the line,
and keeping track of the status of the modem.
Early chips such as the 8250 could only reach speeds of
38,400bps. Newer chips such as the 16450 and 16550A can reach
speeds of 115,200bps with a machine fast enough to handle the
interrupts.
The serial cable which connects your modem to your computer
is comprised of several wires, one for each of the pins that deal
with serial communications. These wires carry signals from the
serial port to the modem, and vice versa, which affect what
things happen and when. For example, if your modem is connected
to another modem, you are connected and a carrier is present.
When a carrier is detected by the modem, it will hold the DCD
(data carrier detect) line high to indicate this to the serial
port. Your program, in turn, can check the serial port for the
status of DCD. If the corresponding DCD bit is set, then you are
connected. Thus, it is very easy for your program to find out
what is happening with the modem simply by checking the serial
port registers.
Some of the more recent versions of the 8250 include the
16550 and the 16550A. Essentially the two are the same, but the
16550 has some bugs and should be treated as a 16450. The reason
that special mention is made of the 16550A is that it contains
something called FIFO buffers. FIFOs can improve the efficiency
of data transmissions by providing a kind of holding area for
characters that need to be sent or characters that have already
been received. BBSkit can make use of these FIFOs it they are
detected on your serial port. FIFO buffers are sometimes a
necessity to reach the full potential of high speed modems.
Additionally, if you are trying to run more than one serial port
at a high speed (greater than 9600bps), FIFO buffers are a
requirement for the computer to be able to keep up with the
serial ports.
The software
A bulletin board can be much more than just a hobby. Some
businesses use it as a means of contacting people that otherwise
would not visit the store, or to provide additional service to
already existing customers.
BBSkit was developed because there were no Turbo Pascal
toolkits that I could find that would address all of the special
needs of writing a BBS or door. The programs provide very
complex user interface. It needs to deal with a human in a
friendly way, it needs to be fast and efficient, and it needs to
be attractive enough to make your BBS successful. The toolkit
itself needs to be written in such a way that users of the
toolkit can expand it, change it, use it any way they want. When
I first began this project in earnest, only one thing came to my
mind: objects. Objects can provide the level of transparency
that I desired for BBSkit. In so doing, we can let the object do
as much of the dirty work as possible, and let you concentrate on
the creative aspect of your application (which is more fun
anyway).
Chapter 3: Introduction to Objects
While reading this section, it is assumed that you are a
fairly experienced Pascal programmer and know how to use records
reasonably well. It would also help to read the appropriate part
of your Turbo Pascal documentation. Chapter 4 (TP 6.0) or
Chapter 9 (BP 7.0) of the User's Guide provides good material for
someone just learning objects. This chapter is not intended as a
substitute for the Borland documentation, but instead as a
supplement. I feel that it is extremely important for you to
know what the object oriented idea of programming is all about.
It will only make your applications easier to debug and follow
months down the road.
The only thing I'd like to say in advance is that objects
are not in any way easy to pick up in a single hour. You need to
think in a totally different way, and their true value may not
come until much later. But read the information carefully, refer
back to your Borland manuals, and by all means don't get
frustrated. It will make the difference in the long run.
What is an object?
Think of a Pascal object just like any other object in our
world. It is defined by certain characteristics and serves some
purpose. A Pascal object is much the same. It contains data in
the form of variables (the characteristics), but it also contains
the procedures and functions to do something with that data (the
purpose). The best way to think of an object is to give an
example that is reasonably common for most Pascal programmers.
I'll use the linked list as an example throughout the rest of
this section.
The typical definition of a linked list will look something
like this:
Type
PNode = ^TNode; { pointer to a node in list }
TNode = record
Data: Integer; { data to stored in the list }
Next: PNode; { pointer to next node }
end;
Var
List: PNode; { points to the first node }
PROCEDURE Create(var Head: PNode);
PROCEDURE Delete(var Head: PNode; Data: Integer);
FUNCTION InList(Head: PNode; Data: Integer):
Boolean;
PROCEDURE Insert(var Head: PNode; Data: Integer);
FUNCTION IsEmpty(Head: PNode): Boolean;
In this example, the record type TNode is one node in our
list, which can be a different length every time we check it.
(That's that point of a linked list, after all.) This node
contains two variables, the first of which is our data, and the
second of which is a pointer to the next node, which also has a
piece of data as well as another pointer. This will continue
until a node has a pointer of nil value, which means we are at
the end of our list. This list is operated on by the three
procedures and two functions which follow the Type and Var
sections in the example above. The procedure Create will
initialize a linked list so it can be used by the other
procedures and functions. Delete will delete the node whose data
value matches the Data variable passed to it. InList returns a
boolean variable which reports whether or not a piece of data
exists in the list. Insert will insert a new piece of data (and
therefore a new node) into the list, sometimes maintaining some
sort of order. IsEmpty returns the empty status of the list (if
there are no nodes, then this is true).
Now, to realize the potential that objects have for a linked
list, imagine being able to combine both the data for the linked
list (the variable List) and the procedures and functions which
operate on it. The object form of our linked list would look
much like the original version, but with a few subtle
differences:
Type
PNode = ^TNode; { pointer to a node in list }
TNode = record
Data: Integer; { data to be stored in list }
Next: PNode; { pointer to the next node }
end;
TList = object
List: PNode;
CONSTRUCTOR Init;
DESTRUCTOR Done;
PROCEDURE Delete(Data : Integer);
FUNCTION InList(Data : Integer) : Boolean;
PROCEDURE Insert(Data : Integer);
FUNCTION IsEmpty : Boolean;
end;
Var
List: TList; { our linked list }
What has changed? Well, the most obvious change is that the
procedures and functions have been moved into the Type
definition. What we have done with this move is encapsulated our
code and data in one entity: the object! About the only thing
that seems to be a benefit from this move is that our procedures
and function (also known as methods since they are part of an
object) do not require a parameter of type PNode to be passed to
them. When you call one of these methods, they already know
exactly which list you are talking about, even if you have
hundreds of them in your application.
Writing such data types as objects also has one other
benefit. Several abstract data types (or ADTs), such as the
linked list, the queue and the stack, have several procedures or
functions common among them all in name or purpose, but they must
do each operation slightly different. So, when you name these
procedures or functions in a non-object implementation, you must
prefix each with a name such as ListCreate or QueueCreate. When
you turn these ADTs into objects, you just name the procedure
Create in every object and let the compiler handle it from there.
Once you get the code debugged and it works, you need only know
that a Create procedure creates some sort of data type. It
really doesn't matter which one because they all do pretty much
the same thing: create an ADT and initialize it for use.
How do objects fit into BBSkit?
All of this must seem pretty pointless. How do objects make
programming a BBS any easier? Well, there are two important
things left out of the preceding section: inheritance and
polymorphism.
Inheritance
Let's say we want to expand our linked list from the
previous section to do a couple more things. It really doesn't
matter what these things are, just the fact that we want the link
to function exactly like the old list with the exception of our
new code. Now, rather than rewriting all of that old code, or
copying the text (which is still the same as rewriting it as far
as compiled code is concerned), wouldn't it be great to just tell
the compiler that we want to use the old list as a base to build
on? Well, we can!
Type
TNewList = object(TList)
PROCEDURE WowMe;
end;
This definition does exactly what we just talked about. It
creates a new object that descends from a previously defined type
and adds one method to it. Now, variables of type TNewList can
access all of the stuff in TList as well as procedure WowMe. The
only code we have to write is for our new method. Everything
else is already written, already debugged, already there. Turbo
does the rest.
Polymorphism
We can write an object and add to it without changing the
original definition. But what if we want our descendant object
to inherit some method that we want to change slightly? What if
we even want to be able to still call the old code? This is
where BBSkit and objects truly become useful.
To polymorph a method of some object, some small changes
needs to be made to the code. Unfortunately, this requires
having the source code to the object you wish to change. For
this reason, if you ever think that you might need to override a
method, design your object accordingly.
Before anything can be polymorphed, two very important
things have to be written into your code that wouldn't normally
be there: the CONSTRUCTOR and DESTRUCTOR methods. Constructor
methods do what you would expect them to: they construct an
object for use. More specifically, they set up the object's
virtual method table, or VMT. The VMT is how the compiler keeps
track of which methods have been overridden and which haven't, so
when your object calls a method it knows where the code really
is.
If you don't call the constructor and you have virtual
methods in your object, your system can completely lock up.
Always call the constructor before any other method.
The keyword virtual will tell the compiled that the method
might need to be overridden sometime, somewhere. Place it after
any method that might be overridden like this:
TList = object
List : PNode;
CONSTRUCTOR Init;
DESTRUCTOR Done; virtual;
PROCEDURE Delete(Data : Integer);
FUNCTION InList(Data : Integer) : Boolean;
PROCEDURE Insert(Data : Integer); virtual;
FUNCTION IsEmpty : Boolean;
end;
In this example, the Done method and the Insert method have
become virtual. Why? What if you need to add some dynamic
variables to a descendant of this object, and they need to be
disposed of when the object is disposed? Dispose of them in the
destructor and you will never have to worry about the variables
being "lost." As for the Insert method, you may want to create a
descendant object which sorts the list contents as they are
inserted. It is only logical to place such code in the Insert
method.
Also remember that once a method is declared virtual, it
must always be declared virtual in the descendant objects as
well. As the Turbo manual say, "once virtual, always virtual."
You can still override non-virtual methods, and the compiler
will not give you an error. These methods, however, are not
virtual, and the new object cannot call the old method, only the
new. Use caution when overriding methods and make sure the
parent method is virtual if you still want to use it.
The last thing to keep in mind is that the procedure Run has
become pretty standard with the introduction of Turbo Vision.
Run is pretty much a "do-all" procedure that repeats itself over
and over until the application is ready to be quitted. If you've
read the Turbo Vision manual, or even just parts of it, you will
probably recognize that this is the main part of almost every
Turbo Vision program:
BEGIN
App.Init;
App.Run;
App.Done;
END.
In this case, the Init method initializes the program and
all the variables to whatever state they need to be in at the
programs start. Done does exactly the opposite; it prepares the
program for quitting by closing all open files and freeing up all
the memory that has been allocated for dynamic variables. Init
and Done are called only once, so it goes to show that Run must
execute the rest of the time the program is running. BBSkit also
makes use of this so that some sort of standard might emerge.
Expanding the stock TBBS object
The three methods which actually control the flow of a
BBSkit program (Init, Done and Run) are all empty in the TBBS
object. Calling them is just like not calling them because there
is nothing in them. So, the first thing you need to do when you
create a descendant of TBBS is to give these methods something to
do.
Init should do whatever things you need done once only.
Unless you can be assured that the modem will never need to be
initialized more than once, setting up the modem is probably not
the thing to do in here. The only exception is to set the modem
to auto answer using the ATS0=x command, where x is some integer
number greater than zero. Your should open the serial port here,
and possibly read in any configuration stuff for your app and
store them in variables in your object.
Done should do pretty much the opposite of Init. Here
should go all code to make sure your system shuts down correctly.
Close all your open files, close down the serial port, make sure
your dynamic variables are all deallocated and then return any
exit code you might want to send to a batch file. This method is
also called only once during the execution of a program. Done
will also handle deallocation of your object.
Run is where your program will spend almost all of its time.
Init and Done will take a very minor amount of time, so if your
program runs for an hour, almost all of it will be spent in this
method. Coding approach is a little different for a BBS
application and terminal applications, so I will cover each in
more detail in chapters 4 and 5. Some general things to remember
are global for any application. BBSkit is ideally suited for an
event-driven application if you like writing those kinds of apps
(which is what Turbo Vision is, by the way). Run could simply be
an event handler, which will call several other methods which
actually get stuff done and then return a code telling Run where
to go next. This type of setup is also great for programs which
want to use overlays, because you can place the code to do things
in a separate unit and then turn those units into an overlay.
This will save on memory and can help make a shell to the
operating system more efficient. BBS apps will especially
appreciate this because they can make more memory available for
on-line doors.
Important things to remember
Objects are a new thing to a lot of people, so if you don't
get it right away, be patient. They are a radically different
approach to programming and it may take a little while to get the
idea of what objects are truly useful for. Object oriented
programming is a great way to get a lot done in little code
because most of the work is already done. Borland's manuals were
a good source of information for me when I was learning objects,
so if you haven't already read those, please do. They will make
more sense out of some of the topics I have discussed in this
manual. This manual should certainly not be used a substitute
for Borland's documentation! They designed the OOP additions to
Turbo Pascal, so they will know what they're talking about better
than I.
Chapter 4: BBS Design
Principles of BBS design
Bulletin boards are complicated beasts. More and more often
the small boards you know and love are slowly turning into power
house systems with multiple lines, and extra benefits for users
that contribute a little cash to the system. These types of
systems aren't just a hobby anymore, they can turn into a full
time business, providing information service features for a lot
less money. It is for this reason that a BBS must be carefully
handled. In either case, there is a lot of time and money
invested in a BBS, and there is no reason that it should fail
because of a poor design. BBSkit tries to do as much of the
dirty work as possible, making sure that users don't exceed time
limits, that they have an environment that works for them instead
of them working around it. You should carry this philosophy into
designing your bulletin board system. Sometimes KISS (keep it
simple, stupid!) makes a whole lot of sense.
Any time you write a BBS, there are some things you should
do before you code a single line. Try to lay everything out
ahead of time, making the most of your ideas on paper. Lay out
your data structures for your config files, user databases, file
areas, message bases, everything. If you have flags for security
levels or just a level number, write down what will be standard
for the flags or levels. Write down what each subsystem of your
BBS will do. It might also be a good idea to write down what
basic commands will be available from each of your subsystems.
Once you have this done, you are a little closer to getting
down and writing code. There are a few more things which need to
be cleared up before you start, though. Are you going to split
your code into separate units, perhaps to create an overlaid BBS?
Or, are you going to make one gigantic executable which will eat
up just as much system memory? For that matter, how much memory
are you going to require for your system? Will you be using an
event-driven method of calling (such as Turbo Vision
application), or are you going to do it some other way? (Objects
go hand in hand with event-driven programming, so this is
something you should seriously consider.)
Perhaps the best way to prepare for writing a BBS is to
closely examine a couple of different systems that have been
successful in your area. Call them up and explore them. Find
out what they do and how they handle things. You'll notice
things that might not immediately come to mind, such as time
limits, color use, how fast their system really is, and maybe the
way they manipulate their message base. If you want you can even
take the feature list from a couple of different systems, pick
out what you like the best, maybe add to it, and then plan on
implementing that in your app.
BBS design using BBSkit
When designing your BBS using BBSkit, you will always want
to override the stock TBBS object. Overriding this object will
enable you to access all of the special features contained in the
object without having to modify the source code. (See the
chapter on objects for information on this subject.) Your new
object will provide the guts to your application, making use of
the provided TBBS methods when needed.
New objects will need to override the Init, Done, and Run
methods, but at the same time remember to call the old ones in
order to keep things running smoothly. Remember that the Run
method should loop until you are ready for your program to return
to DOS. Whenever you return to DOS, it's a good idea (unless you
know what you are doing!) to make absolutely sure that the serial
port is closed down. If it isn't, there is the slight
possibility that incoming characters or changes in the serial
port status lines will cause interrupts to occur when there is no
code to handle them!
Menu loops
Every board that hosts a user and performs various actions
for that user must have a menu loop of some sort. Most boards
have multiple menus: one for the message section, one for the
file section, one for online games, and possibly a "main" menu
that will allow the user to go to any of the other major sections
of the board.
However you code it, you may have lots of menu loops, or you
could have one procedure that handles all the menus in the
system. Whichever the case, there are some very important things
to remember before putting the finishing touches on your system.
As the author of this system, you have to write code that will
handle all sorts of stupid things that users do, like hanging up
on your system suddenly, leaving the computer doing nothing for
ten minutes (and thereby not allowing anyone else to use the
system either) and staying on for excessive amounts of time. The
following segment of code should give you some idea of the stuff
required in a menu loop.
Var
LogOff : Boolean; { when true, log user off
system }
Ch : Char;
begin
LogOff := False;
while (not LogOff) do
begin
Repeat
if (CarrierLost) or (UserInactive) then
LogOff := True;
Until (LogOff) or (Incoming);
if (Incoming) then
begin
Ch := UpCase(ComReadKey);
case Ch of
'M' : MessageMenu;
'F' : FileMenu;
'G' : Games;
'O' : LogOff := True;
end;
end;
end;
end;
In this example, we have several things going on. Our
LogOff boolean simply tells the program if the user needs to be
logged off the system for some reason. This could be because he
hung up on us, or his session is over, or because he specifically
told the system that he was done for this call. In any case,
when LogOff becomes true, this code segment will be swiftly
exited and the program must then handle shutting down this users
session. All other cases will find us within this menu loop,
continually checking to see if the user is on or if his session
is over, or if he pressed a defined key. When a key is pressed
that we know how to handle, the case statement directs us to the
next part of the system.
UserInactive is a boolean function which returns true if a
user inactivity has occurred.
Time limits
Time limits are a good idea to have on any BBS. This keeps
users from taking up ridiculous amounts of time doing their own
thing when other users are most likely anxious to get on
themselves. Generally, time limits will be a requirement for all
users.
Time limits are already directly supported by BBSkit. You
need only tell the system how much time a user should have, and
enable the timing system. The rest is taken care of by BBSkit.
When time expires, the system will treat it the same as an
inactivity time-out. You can check to see if there is any time
left in the user's session to distinguish between a true
inactivity and no time remaining.
Check the TBBS method SetTimeLimit for more information.
Front-end mailers
This is a tricky subject. Front-end mailers exist to port
messages from world-wide networks into your own BBSes message
bases. Most of these mailers can write to a variety of the more
popular message storage formats, such as the one used by QuickBBS
and all of its clones. However, this is not too important a
topic to cover because the style of your message base is your
decision. Also, these mailers generally provide support to write
messages to a generic format, which you can then convert to your
own format using a custom written program.
More to the point, a front-end mailer will answer the phone
for you, determine who is calling (is it a user or another
computer ready to send messages?) and then only transfer control
to your BBS if the caller is a user. In this way, your BBS needs
to set up some type of command line options that allow an outside
program to tell the BBS what is happening. For example, what bps
rate did this new user connect at? If the bps rates aren't
matched, the end user will get a lot of garbage every time you
attempt to send a character out to him or her. Again, the best
solution for this problem would be to look at another BBS that
you see using a front-end mailer. How does it get around this
problem? You can always borrow ideas from something that is
"tried and true."
Front-end mailers generally require a FOSSIL driver for
serial communications. A future version of BBSkit will allow you
to use a FOSSIL in place of the internal routines, making
synchronization with mailers extremely easy.
Emulation
Emulation has been around a long time in the BBS world, but
even longer in the mainframe world. It is also one of the best
things to happen to telecommunications. It's always nice to make
a user feel at home, letting your BBS mimic some of the things
that a PC can do by itself. Emulation is a way of letting your
computer tell a remote computer what to do. Remember that
straight telecommunications can only send and receive characters.
There are no standard ways to tell the remote computer to place
the cursor at a certain spot on the screen. Only some sort of
emulation provides this ability, and even then you have to decide
what type of emulation to use, because all emulations are not
created equal.
By far the most popular emulation in use by BBSes in the
U.S. is ANSI, which is a derivative of DEC VT-100 with additional
support for color and less application/mainframe specific codes.
Any serious BBS needs to support ANSI, and BBSkit takes care of
this nicely. You need only load the template, and your program
supports ANSI for send and receive.
Emulation lets you do a lot of neat things that you normally
cannot do on a BBS. Full screen editors, screen-oriented
systems, full color games, and some other niceties would simply
not exist without emulation.
Tricks and traps
This section will just contain some final words on the topic
of designing your BBS. There are one or two things that will
undoubtedly come up as a result of writing your BBS in Pascal,
which is a procedural language, versus writing it in something
such as BASIC, where your program can go anywhere it wants
anytime it wants. I wrote my first two boards in BASIC on an
Apple II, and it was very easy to handle such things as carrier
loss because I just told the code to "goto" if something went
awry. You can't get away with this type of thing in Pascal.
The easiest way to handle something where your code needs to
bubble upwards to your Run procedure is to use a boolean variable
of some sort. Just check this at the beginning of each
procedure, and only let that procedure execute if the boolean is
of some predefined value (most of the time I'm guessing it will
be false, for example if (not FatalError) or something like it).
If this variable ever becomes the "wrong" value (in our example
it would be true), the code will just end up bubbling back to the
top, where we can easily handle anything bad that has happened.
The three things that immediately come to mind are carrier loss,
inactivity timeout and expiring time limit. All of these will
require some sort of handling just like this. If you come up
with a better way of doing this, by all means let me know and
I'll put it in the next version of this manual!
Starting with version 3.0, a rather non-structured way of
doing this would be to create two tasks using MTASK for each node
in your system. One task (we'll call it the system task) makes
sure things are okay with carrier, time limits and such, while
the other task (the interface task) does all the interfacing. If
something bad happens, the system task kills the interface task
and drops out on its own. Things still work out neatly, but
debugging can be a bear.
Finally, just keep in mind that in writing BBSkit I've tried
to keep everything easy to use. If you have problems with
anything, just override it or let me know what's going wrong and
I'll try to fix it. I can't promise anything, but I'll try. I
firmly believe that powerful, fast, easy to use boards can be
written with a generic toolkit such as BBSkit. If you get stuck,
take a look at Host.Pas, provided on your distribution disk.
It's a reasonably fleshed out host which can give you ideas on
the basics of how a BBS should be approached.
Chapter 5: Terminal Design
Principles of terminal design
Designing a terminal program using a toolkit such as BBSkit
may seem strange at first, but it can be done. After all, the
most important part of your program (the communications routines)
are already written. These routines don't care if your program
is a host or a user because they still send and receive
characters. Additionally, the emulation routines are capable of
maintaining some decent support for emulation unless you want one
hundred percent mainframe compatibility with VT-100. Two
protocols and their derivatives are already included, so you are
actually well on your way to creating a full featured terminal
just by using the available tools. The most important task for
you is now to link these tools together by creating some sort of
interface for the local user. This is where BBS design and
terminal design differ radically; they service opposite ends of
the connection. So, although most of the routines contained in
BBSkit are meant for a BBS, this is only because a BBS requires
more specific support routines. A terminal does little more than
send and receive characters are far as the remote host is
concerned. The rest of the time is spent dealing with the local
user, and the remote host knows nothing about that.
Terminal design using BBSkit
Again, one of the most important things to decide is what
your terminal is going to offer. Get all your ideas down on
paper before you start working, otherwise you'll deadlock trying
to add something later. Design your menus, figure out what you
will offer, and decide on a user interface. Will the terminal be
in text or graphics mode? Are you going to be using a pre-
written user interface such as Turbo Vision or are you writing
your own? Can this interface be used with BBSkit without severe
conflicts? (Remember that Turbo doesn't currently offer anything
like multiple inheritance. So, if you use two objects such as
Turbo Vision and BBSkit together, one of them will have to be the
primary object while the other takes a back seat.)
Getting local commands using TerminalMode
Perhaps the easiest way to use BBSkit in terminal mode is to
use the built in method TerminalMode. TerminalMode is capable of
providing basic terminal characteristics. That is, it will send
characters typed on the local keyboard to the serial port, and
display characters received at the serial port on your screen.
TerminalMode offers full, half, and "chat" duplex modes, as well
as an option to display control characters instead of their
sometimes-cryptic pictures that DOS uses. TerminalMode will exit
as soon as it gets an extended keypress from the local keyboard,
and then return this keypress as the function result. Thus, you
can implement all Alt- combinations as well as PgUp, PgDn and all
the other extended keys as local commands to your terminal
program.
A menu loop for this type of approach would be extremely
simple. In this example, I'll use the fairly standard Alt-X
keypress as a command to exit the program.
Var
Stop : Boolean;
Flags : TTermMode;
begin
Stop := False;
while (not Stop) do
begin
case TerminalMode(Flags) of
#45 : Stop := True; { alt-X }
#73 : Upload; { PgUp }
#81 : Download; { PgDn }
end;
end;
end;
This is a simple example, but it gets the idea across. We
want to catch every keypress and process it if we can. Any keys
not defined in our case statement will just be ignored. They
will not get sent to the serial port. Flags is just a record
while tells TerminalMode how to behave.
Overriding TerminalMode
The only problem with TerminalMode is that it is a basic
function and probably will not satisfy your needs when you start
implementing a truly robust terminal program. The solution is,
as always, to override it. TerminalMode is not a virtual
function because there isn't much you can inherit from it. If
you override it I cannot see you ever needing to call the parent
method. (If you end up needing this for some reason, please tell
me and I'll change it immediately. Until then, you can always
change the source. Just make sure you don't distribute it!)
To remain compatible you should probably allow your new
TerminalMode function to return the extended keypress and let an
outside case statement handle the commands. After all,
TerminalMode is only supposed to handle a terminal session, not
outside events.
Tricks and traps
There are far fewer traps for your code to fall into since
there will always be a user at the console, ready to handle any
events your code isn't designed to handle. For instance, your
terminal never needs to check for an inactivity timeout or
carrier loss. It just reports the status of the serial line and
sends out characters you tell it to. Obviously, you will still
need to debug your program and keep it from hanging and the most
inopportune of times, but this is standard practice for any
program being prepared for public distribution.
Above all, make sure your special features work. These are
what sets your program aside, letting everyone know that it's the
best. However, if the very features which make your program
better make it crash, then your program will earn a bad
reputation. If you add special terminal effects, make sure they
work.
Good luck!
Chapter 6: BBSkit Unit Reference
This chapter provides a reference for all of the procedures,
functions and types that are contained in the BBSkit unit. If
something is new to version 3.0, [New] will be set at the far
right of the item title. Items which have changed since version
2.0 of the toolkit are flagged with [Changed] at the right.
AddIntChar
Declaration: PROCEDURE AddIntChar(Ch: Char);
Adds an interrupt key to the internal list. This internal
list is kept for calls to the method TypeFile, which will exit
immediately if one of these keys is received during the display
of a file. If the case sensitivity flag is set during a
TypeFile, then the case of keys added with AddIntChar will make a
difference. 'A' will not be tripped when the user presses 'a'.
Otherwise, case is ignored.
This capability is especially useful for aborting files
which display a menu of options to the user. When the user
presses a key corresponding to an option, displaying the rest of
the menu can become tedious and time consuming. Using AddIntChar
will allow the menu to be halted as soon as the user presses an
option key.
See Also: ClearIntChars, SetCaseSensitivity.
AddVirtualKey
Declaration: PROCEDURE AddVirtualKey(Code: Char);
Adds an extended keycode to the internal table of those that
can interrupt a ComReadKey operation. This will allow the local
operator to do things behind the remote users's back, such as
adjusting the time remaining, setting security levels, or
initiating a chat with the user.
Use of these keys requires turning virtual keys on through a
call to SetVirtualKeys. Initially this feature is disabled. A
list of the extended keycodes can be found in the back of this
manual in Appendix C.
See Also: ClearVirtualKeys, SetVirtualKeys.
ClearIntChars
Declaration: PROCEDURE ClearIntChars;
Clears the internal list of interrupt characters so that
nothing will interrupt the display of a TypeFile command.
See Also: AddIntChar.
ClearVirtualKeys
Declaration: PROCEDURE ClearVirtualKeys;
Clears the internal list of extended keycodes which can
perform a function on the local terminal without interrupting the
user of the system. These keys can be pressed to perform various
functions during any BBSkit routine which makes use of
ComReadKey. This includes ComReadKeyE and all of the
ComReadLnXXX methods.
See Also: AddVirtualKey.
ClosePort
Declaration: PROCEDURE ClosePort(LowerDTR: Boolean);
virtual;
Closes down the comport associated with the object. The
port must first be initialized with OpenPort before this method
will have any effect on the system. The LowerDTR parameter tells
BBSkit whether or not to lower the DTR line before closing the
port down. On most modems, lowering the DTR line will hang up
the phone.
Override this method to provide any additional functionality
you wish before the port is actually closed down.
See Also: OpenPort.
Cls
Declaration: PROCEDURE Cls; virtual;
Clears the local screen and attempts to do the same on the
remote screen by sending a ^L character over the modem. Most
terminals which do not make use of terminal emulation will
interpret a ^L as a screen clear character. If you are using
emulation, it is a better idea to go ahead and use the EmuClrScr
function to return the correct screen for the remote terminal.
See Also: EmuClrScr (VC unit).
ComReadKey
Declaration: FUNCTION ComReadKey: Char; virtual;
Reads a key from any of the legal input sources while at the
same time switching among the running tasks with MTASK, checking
for active virtual keys, keeping tabs on the active time limit
(if any) and making sure the user is not inactive for
unreasonable amounts of time. This is the basic input function
for all of the BBSkit input routines, including the line input
methods. This method does not echo the key before returning it.
If you need this functionality, use ComReadKeyE.
It will return the character pressed by the user if any, or
#0 if an error condition exists. On return of the null
character, you should check the time limit, the UserInactive
method to see what caused the unexpected dropout.
See Also: ComReadKeyE, ComReadLnXXX, UserInactive.
ComReadKeyE
Declaration: FUNCTION ComReadKeyE: Char; virtual;
Calls ComReadKey to get a character, sends the echo
character to the legal output devices, and returns the character
to the caller. This method will provide all of the error
checking that ComReadKey does, of course, but you still need to
determine the cause of an error on return of the null character
(#0).
See Also: ComReadKey, SetEcho.
ComReadLn
Declaration: PROCEDURE ComReadLn(var Inp: String; Max:
Byte); virtual;
Reads a line of input into the variable parameter Inp by
repeatedly calling ComReadKey. The line cannot exceed Max bytes.
Once this limit is reached during the read, BBSkit will simply
wait for either a backspace to make room for more characters, or
a carriage return to terminate the input line.
The following special characters are recognized during the
input:
#8 ^H Backspace one character (destructive)
#9 ^I Tab over to the next tab stop (every 8
characters)
#13 ^M End the input line
#24 ^X Erase to beginning of line
ComReadLn is actually just a call to ComReadLnDefault with a
null default string.
See Also: ComReadLnDefault, ComReadLnWrap.
ComReadLnDefault [New]
Declaration: PROCEDURE ComReadLnDefault(var Inp: String;
Max: Byte; Default: String); virtual;
Reads a line of input in, but allows the program to specify
a default string of text the user may accept or backspace over to
type something else.
Recognizes the same special keys that the ComReadLn method
does.
See Also: ComReadLn, ComReadLnWrap.
ComReadLnWrap
Declaration: PROCEDURE ComReadLnWrap(var Inp: String; Max:
Byte; var Wrap: String); virtual;
Reads a line of input in with the exception that when the
maximum number of bytes in the line is reached, it will search
back to find the beginning of the current word, place it in the
Wrap variable, and strip it from the line of text returned in
Inp. This essentially means that repeatedly calling this method
will provide the basic wordwrap functionality found in just about
any editor these days.
Call it the first time with Wrap set to a null string or
whatever junk is there will be placed at the front of the new
input line. Also recognizes the same special keys that ComReadLn
does.
See Also: ComReadLn, ComReadLnDefault.
ComWrite
Declaration: PROCEDURE ComWrite(Strn: String); virtual;
ComWrite will send a line of text out of the output devices
you have enabled using SetOutput. This method pays close
attention to the terminal characteristics you have defined for
it, including active emulation templates, line feed handling
after carriage return, nulls for slow terminals and paging
settings if active.
Note that ComWrite does not tack on a carriage return at the
end of the line. If you need this type of behavior, use
ComWriteLn.
See Also: ComWriteLn, SetOutput.
ComWriteLn
Declaration: PROCEDURE ComWriteLn(Strn: String); virtual;
ComWriteLn performs the same function as the ComWrite method
does, with the exception that it tacks a carriage return on to
the end of the string. If line feeds are enabled, a line feed
will also be sent to the terminal after the carriage return.
See Also: ComWrite.
DetectANSI [New]
Declaration: FUNCTION DetectANSI: Boolean;
This function sends a code defined by the ANSI terminal
emulation set to the remote terminal. On receipt of this code,
ANSI terminals are to respond with the coordinates of the cursor.
This makes an easy way of determining if the remote terminal has
ANSI capability without prompting the user. The function will
return True if it finds ANSI at the end of the connection, or
False if nothing shows up within a couple of seconds (more than
reasonable time).
See Also: EmuXXX (VC unit).
Dial
Declaration: PROCEDURE Dial(Number: String); virtual;
Dial will simply send a Hayes command string to your modem
which will cause it to dial the number you have passed to the
procedure. This number is actually just the tail end of an ATD
command, so you can modify it to suit your particular needs. For
example, to force tone dialing place a T in front of the actual
number.
Note this method is virtual. If you do not have a Hayes
compatible modem, or you modem requires special setup before you
can dial, you can override the procedure to make it do what your
hardware requires.
See Also: PickupPhone, SetAnswerMode.
Done
Declaration: DESTRUCTOR Done; virtual;
Gracefully takes the object down, frees up resources that
were being used, and calls the parent Done method to ensure
everything is cleaned up in parent objects as well. Any object
that makes use of TBBS should call Done during their own Done
method to keep everything as clean as possible at runtime.
See Also: Init, Run.
FilterWrite [Changed]
Declaration: PROCEDURE FilterWrite(Strn: String); virtual;
the
the output to the right console.
Additionally, there is support in there now for BBSkit
Session Protocol. Please remember that this protocol is being
phased out of BBSkit and it is strongly recommended that you do
not make it an integral part of your application.
See Also: FilterWrite (VC unit).
FlushSendBuffer [New]
Declaration: PROCEDURE FlushSendBuffer;
A version of the same code from the Comm unit, but this
procedure is multitasking aware and will keep things happily
going in the background until it is time to exit. All it does is
wait until the send buffer for the comport is empty, and then
returns. It will wait forever if need be.
See Also: FlushSendBuffer (Comm unit).
GetAnswerMode
Declaration: FUNCTION GetAnswerMode: TAnswerMode;
Returns the current answer mode for the object. The answer
mode is used by the PickupPhone method to determine what it
should send to the modem to cause it go off-hook. For Hayes
compatible modems, the Originate string is ATD, while the Answer
string is ATA.
See Also: PickupPhone, SetAnswerMode.
GetInput
Declaration: PROCEDURE GetInput(var Con, Rem: Boolean);
Returns the current settings of the input flags. These
flags control who can send input to the input methods of BBSkit.
If Con is True, the console is allowed to enter stuff at the
keyboard, and if Rem is True remote input is accepted from the
comport. These options are set through SetInput.
See Also: ComReadXXX, SetInput.
GetOutput
Declaration: PROCEDURE GetOutput(var Con, Rem: Boolean);
Returns the status of the output flags for the object.
These flags control who is sent the output directed through the
ComWriteXXX methods. When a flag is True, output is sent to that
device. If False, output is masked.
See Also: ComWriteXXX, SetOutput.
HandleVirtualKey
Declaration: FUNCTION HandleVirtualKey(Code: Char):
Boolean; virtual;
Use of this method is rather tricky. It is used by the
ComReadKey method when an extended key on the local console is
pressed (such as the arrow keys, or a function key). When
called, it sends the extended keycode of the key pressed to
HandleVirtualKey, which must then interpret how to handle it. It
may just alter flags, or it may enter into a chat mode.
It must be overridden by your code. Otherwise it does
nothing. The return value is designed to tell ComReadKey if it
should bother continuing to get input. For the majority of
things, this will be False, telling ComReadKey that no it should
not quit getting input. But for certain cases (for example, a
command to log the user out immediately) there is no reason to
continue input, so HandleVirtualKey should return False. This is
a tricky subject, so checking out the example Host.Pas program
may help to clear the smoke.
See Also: AddVirtualKey, SetVirtualKeys.
Hangup
Declaration: FUNCTION Hangup: Boolean; virtual;
This method attempts to put the modem on-hook, essentially
hanging up the phone. It does so by first making an on-off-on
transition of the DTR line, which on most modems causes them to
hang up and return to the command state. If this fails, it will
try to send the +++ attention sequence, followed by the Hayes
standard ATH0 hangup command.
The return value of this method signals you if it was able
to hang up the modem. If there is a carrier at the end of the
method, it returns False, letting you know that the line is not
clear. Otherwise, if everything works out okay, the line is
clear and it will return True.
If your modem will not hangup using any of these approaches,
you may want to override the method and use a command known to
work for your modem. Be aware that a modem which always reports
a carrier will never appear to be successful using this method
(the return value will always be False). You can also try
sending ATX3 to your modem before trying to hangup. This will
tell most modems to recognize the DTR transition (the most
reliable way of hanging up).
See Also: PickupPhone.
Incoming
Declaration: FUNCTION Incoming: Boolean;
Returns the status of input waiting at any of the legal
input devices. Basically, this returns true if anything can be
gotten using a ComReadKey.
See Also: Keypressed (CRT unit), ReceiveBufferEmpty (Comm unit).
Init
Declaration: CONSTRUCTOR Init;
Initializes the TBBS object by calling the parent Init
method, and setting up the values for some internal variables.
Any objects that make use of TBBS should be sure to call Init as
the first action in their own init code, to ensure proper binding
at runtime.
See Also: Done, Run.
OpenPort [Changed]
Declaration: FUNCTION OpenPort(Comport: Byte): Boolean;
OpenPort has been changed slightly for version 3.0 to
interface with the multiport support built into the Comm unit.
The first parameter is actually an index into the array kept by
the Comm unit. The first four values of the array correspond to
the standard COM1 through COM4 familiar to IBM PCs. The fifth
through eighth entries are left for user expansion, perhaps for a
multiport card.
OpenPort also now uses the value of TBBS_BufferSize to
initialize the buffer size for new ports. This value is a typed
constant and can be changed at runtime before a port is opened.
Changing the value after the port is opened does not affect the
buffer size. Keep in mind only one port per object can be
opened. If you need more, you can either continuously close and
open ports, or you can use multiple objects.
See Also: ClosePort, TBBS_BufferSize constant.
PBBS type
Declaration: PBBS = ^TBBS;
PBBS is simply a pointer to the TBBS object type.
See Also: TBBS type.
PickupPhone
Declaration: PROCEDURE PickupPhone; virtual;
PickupPhone is designed to send a command to your modem
instructing it to place the modem off-hook and send the
appropriate tones over the phone line. Hayes compatible modems
will already be compatible with the version of PickupPhone
provided with BBSkit. However, you may wish to override the
method with your own code if your modem requires different
commands.
PickupPhone will send ATD to the modem when it is in
Originate modem, otherwise it will send ATA (when in Answer
mode).
See Also: Dial, SetAnswerMode.
ReceiveXmodem [New]
Declaration: FUNCTION ReceiveXmodem(Mode: Byte; Fname:
PathStr): TError; virtual;
This method performs the exact same function as the
ReceiveXmodem in the Protocol unit, with the exception that any
running time limits are suspended before the upload and resumed
after the upload is complete. This makes it encouraging for
users to upload to your system, as it will not detract from the
time remaining in their session.
See Also: ReceiveXmodem (Protocol unit).
ReceiveYmodem [New]
Declaration: FUNCTION ReceiveYmodem(Mode: Byte; ToPath:
PathStr): TError; virtual;
This method performs the exact same function as the
ReceiveYmodem in the Protocol unit, with the exception that any
running time limits are suspended before the upload and resumed
after the upload is complete. This makes it encouraging for
users to upload to your system, as it will not detract from the
time remaining in their session.
See Also: ReceiveYmodem (Protocol unit).
Run
Declaration: PROCEDURE Run; virtual;
Actually an empty method in the TBBS code, this procedure is
intended to be overridden by your object, which will in turn do
the actual work of your object.
See Also: Done, Init.
SendAT
Declaration: FUNCTION SendAT(Cmd: String): Boolean;
This method sends an AT command to your modem and waits for
the expected "OK" response for up to two seconds. This should be
ample time for your modem to respond, even during the longest
commands (ATZ on my modem takes a little under a second).
Your command must be fully formed. That is, it must be the
full AT command, including the AT prefix, for this method to
work. The return value is whether or not it succeeded. It will
return True if it saw the correct OK response within two seconds,
False otherwise.
SendChar [New]
Declaration: PROCEDURE SendChar(Ch: Char);
This is the generic routine which will send characters out
the serial port which has been opened by the current object. It
checks for handshaking, user inactivity, and full buffers before
sending anything out. Additionally it will happily keep things
going in the background using MTASK.
This method is called by all the output routines when
something needs to be sent out through the serial port.
See Also: SendW (Comm unit).
SetAnswerMode
Declaration: PROCEDURE SetAnswerMode(Status: TAnswerMode);
Sets the answer mode to either Originate or Answer. This is
purely for letting PickupPhone know which tone to send across the
phone line after it goes off-hook. The default is Originate.
See Also: PickupPhone.
SetCaptureFile
Declaration: PROCEDURE SetCaptureFile(Path: ComStr);
Sets the capture file for I/O capturing. Capture is not
actually turned on until you call SetCaptureStatus and turn it on
with a True argument. The only I/O which is captured and sent to
the file is that which is sent out through the standard BBSkit
ComWriteXXX routines. The default file is CAPTURE.TXT.
See Also: SetCaptureStatus, SetPrinter.
SetCaptureStatus
Declaration: PROCEDURE SetCaptureStatus(Status: Boolean);
Either turns capturing on or turns capturing off. Captured
text goes to the file which was previously set using
SetCaptureFile, or CAPTURE.TXT if unset. Existing files are not
overwritten, they are appended. Once turned on, all output sent
to ComWriteXXX will also be redirected to the capture file.
See Also: SetCaptureFile, SetPrinter.
SetCaseSensitivity
Declaration: PROCEDURE SetCaseSensitivity(Status:
Boolean);
Toggles the case sensitivity of the WaitFor routine. When
called with a True argument, WaitFor is case sensitive. "OK"
will not match when WaitFor is called with an "ok" argument.
When case sensitivity is turned off, "OK" is equal to "ok".
See Also: WaitFor.
SetEcho
Declaration: PROCEDURE SetEcho(Ch: Char);
Sets which character is echoed to the remote user when a key
is fetched using ComReadKeyE. By default, the key echoed is the
key pressed. However, there are times when the keys pressed
should not be echoed back for security reasons (for example,
during password entry or modification). In this case, you can
pass a non-null character to SetEcho and that character will be
echoed back after each pressed key. You can turn echoing off
again by passing SetEcho the null character (#0).
See Also: ComReadKeyE.
SetInput
Declaration: PROCEDURE SetInput(Con, Rem: Boolean);
SetInput controls the devices BBSkit is legally allowed to
get input from. The first argument controls whether or not input
from the local keyboard is permitted, while the second argument
controls whether or not input is permitted from the serial port.
The input masking is only performed when ComReadKey or one of the
method which use it is called. It does not affect direct calls
to ReadKey (from the CRT unit) or ReceiveW (from the Comm unit).
See Also: SetOutput.
SetInputCap
Declaration: PROCEDURE SetInputCap(Style: TCapStyle);
Controls the way that ComReadLn and the associated line
input methods capitalize input. There are four different
settings:
NoCaps No changes made to typed text
Upper Converts everything to uppercase
Lower Converts everything to lowercase
Proper Converts the first letter of each word
to upper, everything else lower
Once the cap style is set, it will remain in the same mode
until set again with another style.
See Also: ComReadLnxxx methods.
SetLF
Declaration: PROCEDURE SetLF(Status: Boolean);
Controls whether or not line feeds will be sent after a
carriage return. Most modern terminals require a linefeed in
order to not overwrite the previous line.
See Also: SetNulls.
SetNulls
Declaration: PROCEDURE SetNulls(Num : Byte);
Controls how many null (padding) characters are sent after a
carriage return character. Some old terminals are slow at
updating video, and without an input buffer for the serial line,
they require characters which are expendable to give the video
time to catch up with the serial I/O. Nulls are used for this
purpose. Most of the time this will be set to 0.
See Also: SetLF.
SetOutput
Declaration: PROCEDURE SetOutput(Con, Rem: Boolean);
SetOutput controls the devices that BBSkit is instructed to
send output to. The two standard ones are the console and the
remote user. If Con is set to true, output will be directed
towards the console and will appear on the local screen. If Rem
is true, output will be sent out the serial port and eventually
appear on the remote user's screen.
See Also: SetInput.
SetPaging
Declaration: PROCEDURE SetPaging(Status: Boolean);
Sets whether or not BBSkit will attempt to page output.
When paging is turned on, every time the screen is supposed to be
full, it will pause for the user to hit a key before continuing.
The number of lines it will pause can be set through
SetPagingLines, while the message sent to the user is set through
SetPagingMsg.
See Also: SetPagingLines, SetPagingMsg.
SetPagingLines
Declaration: PROCEDURE SetPagingLines(Num: Byte);
Controls the number of lines per screen so that BBSkit's
paging can operate properly. When paging is turned on (through
SetPaging), every time the line counter reaches just below the
screen length, it will pause and wait for user input before
continuing.
See Also: SetPaging, SetPagingMsg.
SetPagingMsg
Declaration: PROCEDURE SetPagingMsg(Msg: String);
Sets the message displayed to the user when a page fills up.
This message should only be a single line, and preferably less
than 10 or so characters long. It will be displayed when a user
reaches the end of a page and should prompt the user to press a
key before continuing output.
See Also: SetPaging, SetPagingLines.
SetPrinter
Declaration: PROCEDURE SetPrinter(Status: Boolean);
Sets the printer status for output. When True, any output
sent out through the standard BBSkit output functions will also
be directed towards the standard printer, LPT1:. This is the
same printer that Turbo Pascal uses in the Printer unit, so if
your printer works in other Pascal programs, it will work with
BBSkit.
See Also: ComWrite, ComWriteLn, SetCaptureFile, SetCaptureStatus.
SetTimeLimit
Declaration: PROCEDURE SetTimeLimit(Min: Word);
Sets the time limit for the user in minutes. As soon as
this method is called, the time limit is set and the countdown
will begin immediately. To stop the timer you have to call
SetTimeLimitStatus with a false argument. To restart the timer,
call SetTimeLimitStatus with a true argument.
See Also: SetTimeLimitStatus.
SetTimeLimitStatus [New]
Declaration: PROCEDURE SetTimeLimitStatus(Status:
Boolean);
Enables or disables the user time limit based on the Status
argument. If the argument is True, the countdown timer is
started, if False, it is stopped.
See Also: SetTimeLimit.
SetTimer
Declaration: PROCEDURE SetTimer(Status: Boolean);
Controls the inactivity timer contained in BBSkit. When
True, the inactivity timer will watch for activity from the user
during input routines, and if the timeout period goes by without
a keypress, a warning message will be displayed and the user
given a last chance to do something or be logged out. If False,
no inactivity checking is performed.
See Also: SetTimerDelay, SetTimerMsg.
SetTimerDelay
Declaration: PROCEDURE SetTimerDelay(Dly: Word);
Sets the number of seconds that the user can be inactive
before a warning is issued signaling a pending logout. The user
is given 15 additional seconds after the warning is given, and if
no activity shows up, the user is logged out.
See Also: SetTimer, SetTimerMsg.
SetTimerMsg
Declaration: PROCEDURE SetTimerMsg(Msg: String);
Sets the message which is sent to the user when an
inactivity timeout occurs. This message should let the user know
that a logout is pending and that they have a short period of
time to do something before being logged out. The default
message is "Hello?" followed by a bell (#7) character.
See Also: SetTimer, SetTimerDelay.
SetVirtualKeys
Declaration: PROCEDURE SetVirtualKeys(Status: Boolean);
Sets whether or not virtual keys are handled by the BBSkit
input routines. Virtual keys are by default turned off, so if
you add them to your application you must enable them with a call
to this method.
See Also: AddVirtualKey, ClearVirtualKeys, HandleVirtualKey.
TAnswerMode type
Declaration: TAnswerMode = (Answer, Originate);
Used by the GetAnswerMode and SetAnswerMode methods for
getting and setting the answer mode, respectively. The answer
mode is used by BBSkit when PickupPhone is called and decides
what will be sent to the modem to pickup the phone. Usually this
will be ATA for answer mode, and ATD for originate mode.
See Also: GetAnswerMode, PickupPhone, SetAnswerMode.
TBBS object [Changed]
Declaration: TBBS = object
This declaration of the TBBS type is very abbreviated
because of the many methods which are contained in the object
itself. Here is a list of all of the methods available in a TBBS
object, and where they originated. Virtual methods are
identified by italics. The method originates in the TBBS object
unless otherwise stated.
AddBatch [Protocol] AddIntChar
AddVirtualKey AverageCps [Protocol]
BatchFile [Protocol] CarrierLost [Protocol]
ClearBatch [Protocol] ClearIntChars
ClearVirtualKeys ClosePort
CloseWindow [VC] ClrEOL [VC]
ClrScr [VC] Cls
ComReadKey ComReadKeyE
ComReadLn ComReadLnDefault
ComReadLnWrap ComWrite
ComWriteLn Delay [VC]
DeleteFromBatch [Protocol] DelLine [VC]
DetectANSI Dial
Done EmuClrEOL [VC]
EmuClrEOS [VC] EmuClrScr [VC]
EmuClrTop [VC] EmuColor [VC]
EmuCursorDown [VC] EmuCursorLeft [VC]
EmuCursorRight [VC] EmuCursorUp [VC]
EmuDelChar [VC] EmuDelLine [VC]
EmuGotoXY [VC] EmuInsChar [VC]
EmuInsLine [VC] EmuNormal [VC]
EmuReverse [VC] EmuScrollDown [VC]
EmuScrollUp [VC] FilesInBatch [Protocol]
FilterWrite FilterWriteLn [VC]
FlushSendBuffer GetAnswerMode
GetInput GetOutput
GetScreenWord [VC] GetText [VC]
GetTextBackground [VC] GetTextColor [VC]
GotoXY [VC] HandleVirtualKey
Hangup HideTextCursor [VC]
HighVideo [VC] Incoming
Init InsLine [VC]
IntegerVal Keypressed [VC]
LoadEmulation [VC] LoadEmulationLib [VC]
LowVideo [VC] NormVideo [VC]
OpenPort OpenWindow [VC]
PickupPhone PutScreenWord [VC]
PutText [VC] ReadKey [VC]
ReceiveXmodem ReceiveYmodem
Run SendAT
SendChar SendInteger
SendXmodem [Protocol] SendYmodem [Protocol]
SetAnswerMode SetBSP
SetCaptureFile SetCaptureStatus
SetCaseSensitivity SetEcho
SetInput SetInputCap
SetLF SetNulls
SetOutput SetPaging
SetPagingLines SetPagingMsg
SetPrinter SetTimeLimit
SetTimeLimitStatus SetTimer
SetTimerDelay SetTimerMsg
SetVirtualKeys SetWindowTitle [VC]
ShowTextCursor [VC] TerminalMode
TextBackground [VC] TextColor [VC]
TextMode [VC] TranslateString [VC]
TypeFile TypeFileParseLine
TypeRestOfFile UserInactive
ValidString [VC] vcReadLn [VC]
vcWrite [VC] vcWriteLn [VC]
WaitFor WhereX [VC]
WhereY [VC] Window [VC]
WindowHeight [VC] WindowWidth [VC]
There are also several variables declared in the private
section of the object. These variables are internal to the
working of the TBBS object and do not affect the use of variables
in your own code.
See Also: TBBS methods.
TBBS_BufferSize constant [New]
Declaration: TBBS_BufferSize: Word = 5120;
This value is used by the OpenPort method to set the size of
the input and output buffers while using the internal
communications routines. The default is 5k, but you may change
it to any value prior to initializing the port. Once
initialized, however, the value is fixed.
See Also: OpenPort.
TCapStyle type
Declaration: TCapStyle = (NoCaps, UpperCase, LowerCase,
Proper);
Used by the SetInputCap method and the ComReadLn routines to
define how inputted text will be formatted.
NoCaps will let all input through untouched. UpperCase and
LowerCase convert all keystrokes to upper or lower case,
respectively. Proper will capitalize the first letter of each
word, and lowercase the rest of the string.
See Also: ComReadLn methods, SetInputCap.
TDuplex type
Declaration: TDuplex = (Full, Half, Chat);
Used in the TTermMode record to define how the TerminalMode
method will echo characters back to the local console. Full
echoes no characters, while Half and Chat will echo each
character as it is typed. Additionally, Chat duplex will issue a
linefeed after each carriage return.
See Also: TerminalMode method, TTermMode type.
TerminalMode [Changed]
Declaration: FUNCTION TerminalMode(Flags: TTermMode):
Char;
keypress.
keypress. An extended keypress are those that return a leading
#0 (null) character to the CRT unit ReadKey function. This
allows all of the normal keys to be sent through to the remote
site, without taking up one for an exit key.
This type of functionality also allows TerminalMode to be
expanded without editing the method itself. You can define
macros simply by running a case statement on the result of the
TerminalMode method, and sending strings out on the receipt of
certain keys. Other keys can change the bps rate, the duplex,
backspace handling, uploads/downloads, or exiting the program.
TerminalMode can be called repeatedly after each extended
keypress is handled to keep things moving.
See Also: TTermMode record.
TTermMode record [New]
Declaration: TTermMode = record
Duplex : TDuplex;
ShowControls : Boolean;
Backspace : Char;
end;
This record structure is used by the TerminalMode method to
provide some flexible functionality to a terminal session. It
allows you to define the duplex of a connection (if and how
characters are echoed to your local terminal), whether or not
control characters are displayed as-is or if they are converted
to inverse uppercase, and lastly what character to send when a
backspace is typed on the local terminal.
For example, some terminals like seeing a #8 character (^H)
as a backspace, while others prefer to use #127 (RUB, or ^? on
some machines).
See Also: TDuplex type, TerminalMode method.
TypeFile [Changed]
Declaration: PROCEDURE TypeFile(Fname: String);
Works much like the DOS TYPE command. Will open a file,
read a block from it, and send it out the legal output devices.
With 3.0, functionality has been added for some measure of
scripting capability inside text files. Before a line is
printed, it is sent through TypeFileParseLine, which can pick a
block of text apart, substituting text strings for token keywords
TypeFile will also quit on keys contained in the list of
interrupt keys.
See Also: TypeFileParseLine, TypeRestOfFile.
TypeFileParseLine [New]
Declaration: FUNCTION TypeFileParseLine(Strn: String):
Boolean; virtual;
Parses and outputs a text string to the standard output
devices. There are several things that this method must do
before exiting back to the calling code:
Parse the text string, substituting text strings for
any tokens defined by the application.
Output the text string, one character at a time.
Check to see if any keypresses exist in the buffer. If
they do, find out if any of them exist as interrupt
keys, and if they do, quit with a True return value.
Return False if there were no problems.
Look through the example code in the BBSKIT.PAS file for
hints on how to write your own parsing routine. The stock
version does no parsing, but parsing is a simple matter of
checking for existing token strings and replacing them with new
text. Tokens should start with some unusual character or be
bound in some way. For example, the token for a user's name
could be %USERNAME or {USERNAME}.
See Also: TypeFile, TypeRestOfFile.
TypeRestOfFile [New]
Declaration: PROCEDURE TypeRestOfFile(var F: Text);
This method takes an already opened text file, and outputs
the rest of it to the legal output devices. This is very useful
for opening a menu, reading the list of interruptable keys, and
then outputting the rest of the file to the output devices.
Please note that since you opened the file, you are expected
to close it! Also, there will be problems with text files that
do not force a carriage return at least every 254 characters. An
example of one program which does not produce hard carriage
returns is TheDraw, which is used for many ANSI screen art files.
See Also: TypeFile, TypeFileParseLine.
UserInactive [New]
Declaration: FUNCTION UserInactive: Boolean;
Returns a boolean variable which lets you know if a user
inactivity timeout has occurred. When it returns with a True
value, you are expected to handle it and log the user off of your
system.
See Also: CarrierLost (Protocol unit), SetTimer.
VersionID [New]
Declaration: FUNCTION VersionID: String;
Returns a string detailing the version and revision
information for BBSkit.
See Also:
WaitFor
Declaration: FUNCTION WaitFor(Strn: String; MaxTime:
Word): Boolean;
Waits for a specified string for a maximum interval of
MaxTime seconds. This method is also set up to wait forever if
passed an argument of 0 for MaxTime. Case sensitivity of this
method is controlled by the value passed to the
SetCaseSensitivity method. When True, "OK" will not match "ok".
When False, they are identical strings as far as WaitFor is
concerned.
Returns True if the string was seen within the allowed time,
False otherwise.
See Also: SetCaseSensitivity.
Chapter 7: Protocol Unit Reference
BufferSize
Declaration: BufferSize = 20480;
Defines the size of the buffer used during transfers. The
buffer only exists during a transfer and is allocated from the
heap. This value must be a multiple of 1024 bytes (which is the
largest packet used by the engine at this writing).
See Also:
CarrierLost
Declaration: FUNCTION CarrierLost: Boolean;
Checks the COM port ErrorFlg carrier lost bit. If a carrier
does not exist when it once did, this function will return True,
signaling that you need to handle the user logoff procedure.
This function is defined here but it also available in all
descendent objects.
See Also:
Done
Declaration: DESTRUCTOR Done; virtual;
Object destructor for the protocol engine. This method
should be called when the object is no longer needed in order to
clean things up.
It will call the Done destructor from the parent
TVirtualConsole object type.
See Also: Init.
Init
Declaration: CONSTRUCTOR Init;
This is the object constructor for the protocol engine. It
sets up some internal variables and prepares most of the object
for use. You must call this constructor in order to properly set
up the virtual method table at runtime.
This method is inherited and overridden from the
TVirtualConsole object.
See Also: Done.
ReceiveXmodem
Declaration: FUNCTION ReceiveXmodem(Mode: Byte; Fname:
PathStr): TError; virtual;
Receives a single file using the Xmodem protocol to the file
named in Fname. The file cannot exist or an error condition will
result. Returns the error which caused the transfer to fail, or
NoError if things went okay.
The Mode variable is made up of one or more of the transfer
constants defined in this unit. You can combine two or more of
the constants by ORing them together (i.e. CRC OR Turbo).
See Also: SendXmodem, TError type, Transfer constants.
SendXmodem
Declaration: FUNCTION SendXmodem(Mode: Byte; Fname:
PathStr): TError; virtual;
Sends a single file using the Xmodem protocol. Fname must
exist and not be a directory. Returns the error condition which
caused the transfer to fail, or NoError if the transfer was
successful.
The Mode variable controls which flavor of Xmodem will be
used. Note that the Turbo modifier cannot be used during an
Xmodem send; therefore the only legal values for Mode are
Checksum, CRC, or OneK. ORing these together won't affect a
transfer since they are all mutually exclusive.
See Also: ReceiveXmodem, TError type, Transfer constants.
TError type
Declaration: TError = (NoError, TimeOut, TooManyErrors,
Aborted, DiskError, NoCarrier, FileExists,
FileNotFound);
This enumerated type defines the various error conditions
that are returned by the protocol after a transfer has either
succeeded (NoError) or failed (any of the others). There is also
a variable in all batch items that defines the error code. This
error code will be NoError for all transfers up to the one that
failed, which will contain the reason the transfer ultimately
failed.
See Also: TBatchItem type.
Transfer constants
Declaration: (in Const block)
BBSkit.
BBSkit.
Turbo = $80 Auto-ACK for receive only; no error checking
is performed.
Xmodem
Checksum = $00 128 byte packets + 8-bit checksum error
detection & correction.
CRC = $01 128 byte packets + 16-bit CRC error detection
& correction.
OneK = $03 1024 byte packets + 16-bit CRC error
detection & correction.
Ymodem
Normal = $00 1024 byte packets, 16-bit CRC error
detection & correction, batching.
Streaming = $01 1024 byte packets, 16-bit CRC error
detection (no correction), batching.
These constants can be passed to the protocol methods in
combination by using the OR operator.
See Also:
Chapter 8: VC Unit Reference
What is a virtual console?
BBSkit 3.0 introduces something borrowed from the Linux
project, a free UNIX for 386-class machines or better: virtual
consoles. A virtual console is a way of allowing more than one
session to run on a single terminal, or in our case, allow more
than one video screen/keyboard combination to be accessed on a
single machine.
The most obvious use for such a thing as this is for
multiple nodes running on a single machine. Virtual consoles in
BBSkit take advantage of the MTASK unit to provide task switching
in the background and to keep things running smoothly. You can
switch among the various virtual consoles by using the left Alt
key in combination with the F1 through F10 keys, for a total of
ten virtual consoles.
Since each virtual console has it's own keyboard buffer and
it's own video memory, it is necessary to redefine virtually all
of the procedures found in the CRT unit with ones that will work
with MTASK and write to the correct virtual console instead of
the physical video memory provided by your video card. This way
you can switch to a console and instantly see where a user is,
without having to wait for any output to give you a clue about
what's going on.
The methods in the TVirtualConsole object provided in this
unit operate only on the console that it is attached to. That
is, calling HideTextCursor will only hide the text cursor on the
display if the console which requested it is visible on the local
screen. Otherwise it happily takes care of things in the
background.
Remember that you can switch among the consoles using the
left Alt key in combination with the functions keys F1 through
F10. You can add more consoles if you need them and feel like
hacking the system task (not recommended).
AllowVCSwitching
Declaration: PROCEDURE AllowVCSwitching(Status: Boolean);
Ordinarily, you can switch among the virtual consoles
(active or inactive) by using the left Alt key in combination
with F1 through F10. If for some reason you do not wish to have
any other virtual consoles except the first one accessible, you
can disable switching among them. If AllowVCSwitching is called
with a True argument, switching is allowed. Otherwise it is
suppressed.
See Also:
CloseWindow
Declaration: PROCEDURE CloseWindow;
Closes the most recently opened window on the console, if
any. It will replace the text that was there before the window
was opened, keeping everything looking as nice as it can.
See Also: OpenWindow.
ClrEOL
Declaration: PROCEDURE ClrEOL;
Clears text from the cursor to the end of the current line.
The current text background is used to fill in the empty spaces.
Note: only performs this action on the local console, not on the
remote screen!
See Also: EmuClrEOL.
ClrScr
Declaration: PROCEDURE ClrScr;
Clears the local console's screen and places the cursor at
(1,1).
See Also: EmuClrScr.
Color constants
Declaration: (in Const block)
The following constants are defined in the VC unit for use
by calls to TextColor and TextBackground.
Black = 0 DarkGray = 8
Blue = 1 LightBlue = 9
Green = 2 LightGreen = 10
Cyan = 3 LightCyan = 11
Red = 4 LightRed = 12
Magenta = 5 LightMagenta = 13
Brown = 6 Yellow = 14
LightGray = 7 White = 15
Blink = 128
Using the Blink attribute by ORing it with the color used in
calls to TextBackground will cause the foreground text to blink.
See Also: TextBackground, TextColor.
Delay
Declaration: PROCEDURE Delay(MS: Word);
This version of Delay waits the specified number of
milliseconds before returning to the caller. Note that this
procedure is only accurate to 55ms since it uses the system timer
tick as a measure of elapsed time. You should use this in place
of CRT.Delay whenever you are using virtual consoles to ensure
that the background task switching keeps going while a delay is
expiring.
See Also: CRT.Delay.
DelLine
Declaration: PROCEDURE DelLine;
Deletes the line that the cursor is on and pulls the lines
below it up one line each. The blank text at the bottom of the
screen is replaced with the current text background attribute.
See Also: EmuDelLine, InsLine.
Done
Declaration: DESTURCTOR Done; virtual;
Deallocates all of the memory associated with the virtual
console and disposes of the object. The biggest gain in memory
terms that calling Done will give you is the freeing of the
memory which is used to store text information while the console
is in the background.
See Also: Init.
EmuClrEOL
Declaration: FUNCTION EmuClrEOL: String;
Returns a string containing the code required by the
emulation template to clear text from the cursor to the end of
the current line. The blanks are filled with the current text
background.
See Also: ClrEOL.
EmuClrEOS
Declaration: FUNCTION EmuClrEOS: String;
Returns a string containing the code required to clear text
from the cursor to the end of the screen.
See Also:
EmuClrScr
Declaration: FUNCTION EmuClrScr: String;
Returns a string containing the code required to clear the
entire screen and place the cursor at coordinate (1,1).
See Also: ClrScr.
EmuClrTop
Declaration: FUNCTION EmuClrTop: String;
Returns a string containing the code required to clear text
from the cursor to the top of the screen.
See Also:
EmuColor
Declaration: FUNCTION EmuColor(Fore, Back: Byte): String;
Returns a string containing the code required to change the
current color attribute used for writing text to the local and
remote screens to a foreground color of Fore and a background
color of Back. If you want text to blink, OR the background
color with the Blink constant.
See Also: TextBackground, TextColor.
EmuCursorDown
Declaration: FUNCTION EmuCursorDown(Num: Byte): String;
Returns a string containing the code required to move the
cursor down Num rows. It will not move past the bottom of the
screen.
See Also: GotoXY.
EmuCursorLeft
Declaration: FUNCTION EmuCursorLeft(Num: Byte): String;
Returns a string containing the code required to move the
cursor left Num columns. It will not move past the left edge of
the screen.
See Also: GotoXY.
EmuCursorRight
Declaration: FUNCTION EmuCursorRight(Num: Byte): String;
Returns a string containing the code required to move the
cursor Num columns to the right. It will not move the cursor
past the right edge of the screen.
See Also: GotoXY.
EmuCursorUp
Declaration: FUNCTION EmuCursorUp(Num: Byte): String;
Returns a string containing the code required to move the
cursor up Num rows. It will not move the cursor past the top
edge of the screen.
See Also: GotoXY.
EmuDelChar
Declaration: FUNCTION EmuDelChar(Num: Byte): String;
Returns a string containing the code required to delete Num
characters, starting with the one under the cursor. It fills in
the right edge of the row with a blank, and will not wrap
characters from rows below. The cursor does not move during this
action.
See Also: EmuDelLine, EmuInsChar.
EmuDelLine
Declaration: FUNCTION EmuDelLine(Num: Byte): String;
Returns a string containing the code required to delete Num
rows, starting with the one the cursor is on. It will pull the
rows below up to fill the gap, and fill the bottom rows of the
screen with blanks. The cursor does not move during this action.
See Also: DelLine, EmuDelChar, EmuInsLine.
EmuGotoXY
Declaration: FUNCTION EmuGotoXY(ToX, ToY: Byte): String;
Returns a string containing the code required to move the
cursor to the absolute coordinate (ToX,ToY).
See Also: GotoXY.
EmuInsChar
Declaration: FUNCTION EmuInsChar(Num: Byte): String;
Returns a string containing the code required to insert Num
characters in front of the cursor. Characters on the end of the
row will be pushed off and lost, and will not wrap around to the
next row. The cursor does not move during this action.
See Also: EmuDelChar, EmuInsLine.
EmuInsLine
Declaration: FUNCTION EmuInsLine(Num: Byte): String;
Returns a string containing the code required to insert Num
rows in front of the one the cursor is on. Rows at the bottom
will be pushed off and lost, and the screen will not scroll. The
cursor does not move during this action.
See Also: EmuDelLine, EmuInsChar, InsLine.
EmuNormal
Declaration: FUNCTION EmuNormal: String;
Returns a string containing the code required to reset the
text attributes to their "normal" values. For virtual consoles,
default text attribute is light gray text on a black background.
See Also: EmuColor, EmuReverse, NormVideo.
EmuReverse
Declaration: FUNCTION EmuReverse: String;
Returns a string containing the code required to switch the
foreground and background text colors.
See Also: EmuColor, EmuNormal.
EmuScrollDown
Declaration: FUNCTION EmuScrollDown(Num: Byte): String;
Returns a string containing the code required to scroll the
entire screen down Num rows. The cursor does not move during
this action.
See Also: EmuScrollUp.
EmuScrollUp
Declaration: FUNCTION EmuScrollUp(Num: Byte): String;
Returns a string containing the code required to scroll the
screen up Num rows. The cursor does not move during this action.
See Also: EmuScrollDown.
FilterWrite
Declaration: PROCEDURE FilterWrite(Strn: String); virtual;
Writes a string of text to the console after first filtering
it through the emulation template. This turns emulation codes
into the actual action meant by an emulation string.
This method is virtual so that descendant objects can add
checks for special codes and/or responses. For example, the TBBS
object overrides this to provide support for BSP and some VT-100
response functionality.
See Also: FilterWriteLn.
FilterWriteLn
Declaration: PROCEDURE FilterWriteLn(Strn: String);
Performs the same emulation filtering that FilterWrite does,
but adds a carriage return/linefeed pair onto the end of the
text.
See Also: FilterWrite.
GetScreenWord
Declaration: PROCEDURE GetScreenWord(AtX, AtY: Byte; var
Ch: Char; var Attr: Byte);
Gets the word which defines the character and color
attribute for the cell at (AtX, AtY). These are absolute
coordinates, and are not relative to the current window on-
screen. On return, Ch will contain the character at that cell,
and Attr will contain the attribute byte.
See Also: GetText, PutScreenWord.
GetText
Declaration: PROCEDURE GetText(X1, Y1, X2, Y2: Byte; Dest:
Pointer);
Gets a block of text data from the console's video memory
and places it in memory pointed to by Dest. The memory must have
been allocated before the call to GetText. You can figure out
the proper size for a given rectangle of text using either the
TextMemSize function, or by using this formula:
[(X2 - X1) + 1] * [(Y2 - Y1) + 1] + 2
See Also: GetScreenWord, PutText.
GetTextBackground
Declaration: FUNCTION GetTextBackground: Byte;
Returns the current text background attribute, masked from
the TextAttr variable kept by each virtual console object.
Values with the 8th bit set (values greater than 127) have blink
enabled for text.
See Also: EmuColor, GetTextColor, TextBackground.
GetTextColor
Declaration: FUNCTION GetTextColor: Byte;
Returns the current text color attribute, masked from the
TextAttr variable kept by each virtual console object.
See Also: EmuColor, GetTextBackground, TextColor.
GotoXY
Declaration: PROCEDURE GotoXY(ToX, ToY: Byte);
Repositions the cursor at coordinate (ToX,ToY), relative to
the current window. (1,1) is defined as the upper left hand
corner of the window.
See Also: EmuGotoXY.
HideTextCursor
Declaration: PROCEDURE HideTextCursor;
Hides the text cursor on the console. Does not affect the
remote screen or any other consoles. The method it uses to
achieve this trick is to place the ending scanline of the cursor
before the beginning scanline. On some video cards this will
result in a split cursor, with a single scanline at the top and
bottom of the cursor cell.
See Also: ShowTextCursor.
HighVideo
Declaration: PROCEDURE HighVideo;
Sets the high intensity bit for foreground text only. Does
not affect the remote terminal in any way.
See Also: LowVideo, NormVideo.
Init
Declaration: CONSTRUCTOR Init;
Allocates memory and sets up the virtual method table for
the object. This method must be called before any other method
from the object can be used, or you're asking for trouble.
See Also: Done.
InsLine
Declaration: PROCEDURE InsLine;
Inserts a blank line where the cursor is, pushing the lines
below it down one. The blank line is filled with the current
text attribute.
See Also: DelLine, EmuInsLine.
Keypressed
Declaration: FUNCTION Keypressed: Boolean;
Returns True if there are any keys waiting in the internal
key buffer for the console. It will return False if there are no
keys waiting.
See Also: ReadKey.
LoadEmulation
Declaration: FUNCTION LoadEmulation(Fname: String):
Boolean;
Attempts to load the emulation template in Fname into the
emulation template record for the console. If it is successful,
it will return True. Otherwise it will return False and the
previous emulation template will remain in use.
See Also: LoadEmulationLib.
LoadEmulationLib
Declaration: FUNCTION LoadEmulationLib(Key, Lib: String):
Boolean;
Attempts to load the emulation template from a library file.
The library file is pointed to by Lib while Key defines the
keyname to look for in that library. The keyname usually is the
filename which would be used if the template were in its own
file. If it is successful, it will return True. Otherwise it
will return False and the previous emulation template will remain
in use.
See Also: LoadEmulation.
LowVideo
Declaration: PROCEDURE LowVideo;
Clears the high intensity bit of the foreground color on the
local console.
See Also: HighVideo, NormVideo.
MaxKeyBuffer constant
Declaration: MaxKeyBuffer = 32;
This value defines the maximum number of keystrokes that are
permitted in the keyboard buffer for each virtual console. It is
preset at 32. This capability works by checking the DOS key
buffer at each iteration of the main system task, and putting
keystrokes into the current console's buffer. Note that an
extended keypress, such as PgUp, actually represents two
keystrokes, the null (#0) prefix character and the actual key
code.
This value must be a power of 2 due to the way the code
handles the array wraparound.
See Also:
NormVideo
Declaration: PROCEDURE NormVideo;
Changes the text attribute to the default of light gray text
on a black background.
See Also: HighVideo, LowVideo.
OpenWindow
Declaration: PROCEDURE OpenWindow(X1, Y1, Width, Height,
Fore, Back: Byte; Border: TBorder; Title:
String);
Opens a text window on the screen using the parameters given
to it. (X1,Y1) defines the upper left corner of the window, in
absolute coordinates. Width and Height are the width and height
of the writable area of the window. This does not include the
border, if any. Fore and Back are the default colors used by the
window, which allow you to give it an appearance more like a
window. Border defines the type of border used, if any. Title
is the default title for the window, which will only be visible
if the window has a border.
Note that windows which are opened are closed in reverse
order, and there is currently no support for switching among
multiple overlapping windows.
See Also: CloseWindow, TBorder type.
PutScreenWord
Declaration: PROCEDURE PutScreenWord(AtX, AtY: Byte; Ch:
Char; Attr: Byte);
Puts a character and attribute combination directly into the
console's video memory at the character cell defined by
(AtX,AtY). This coordinate is absolute and is not affected by
any active windows.
See Also: GetScreenWord, PutText.
PutText
Declaration: PROCEDURE PutText(AtX, AtY: Byte; Source:
Pointer);
Puts a block of text previously saved with a call to GetText
directly into the console's video memory. The upper left corner
of the block is defined by (AtX,AtY). This coordinate is
absolute and is not affected by any active windows on the
console.
See Also: GetText, PutScreenWord.
ReadKey
Declaration: FUNCTION ReadKey: Char;
Patiently waits for a character to appear in the console
keyboard buffer and then returns it. ReadKey is task switching
friendly and will continue to switch among background tasks while
it is waiting for a character to appear in the buffer.
See Also: Keypressed, vcReadLn.
SetWindowTitle
Declaration: PROCEDURE SetWindowTitle(Title: String);
Changes the window title to a new string. This is updated
on-screen immediately.
See Also: OpenWindow.
ShowTextCursor
Declaration: PROCEDURE ShowTextCursor;
Unhides the text cursor on the console by redefining the
cursor dimensions back to the defaults for the type of card found
on the system. Usually this is the bottom two scanlines of the
cursor.
See Also: HideTextCursor.
SystemLoad variable
Declaration: SystemLoad: Real;
The value in this variable is an attempt to mimic the UNIX
'uptime' command, which provides a number representing the
current load being placed on the system. This version of the
load is a measure of how many milliseconds elapse between
iterations of the system task. The lower the number the better.
It is provided for amusement only, and has not undergone much
rigorous testing.
See Also:
TBorder type
Declaration: TBorder = (NoBorder, SingleLine, SingleTop,
DoubleLine, DoubleTop);
TBorder is an enumerated type used by the
TVirtualConsole.OpenWindow method. It defines the type of border
which will be used for the new window, if any.
See Also: TVirtualConsole.OpenWindow.
TEmulation record
Declaration: TEmulation = record
Name : String[20];
Key : String[8];
Header : String[3];
Offset : Byte;
XYOrder : Boolean;
ClrEOL : TCmdStr;
ClrEOS : TCmdStr;
ClrScr : TCmdStr;
ClrTop : TCmdStr;
Color : TCmdStr;
CursDn : TCmdStr;
CursLf : TCmdStr;
CursRt : TCmdStr;
CursUp : TCmdStr;
DelLine : TCmdStr;
DelChar : TCmdStr;
GotoXY : TCmdStr;
InsChar : TCmdStr;
InsLine : TCmdStr;
Normal : TCmdStr;
Reverse : TCmdStr;
ScrlDn : TCmdStr;
ScrlUp : TCmdStr;
end;
This record holds the information for an emulation template.
The TCmdStr type is defined as
TCmdStr = String[2];
Each member of the record is described in more detail below.
Name Long name of the emulation template.
Key Keyname, usually the same as the DOS
filename.
Header Header, if any, sent before each
emulation code.
Offset Offset for computing GotoXY codes.
XYOrder True = X,Y; False = Y,X
ClrEOL Clear cursor to end of line.
ClrEOS Clear cursor to end of screen.
ClrScr Clear screen.
ClrTop Clear cursor to top of screen.
Color Change color.
CursDn Cursor down.
CursLf Cursor left.
CursRt Cursor right.
CursUp Cursor up.
DelChar Delete character at the cursor, pull
line left.
DelLine Delete line with cursor, pull lines up.
GotoXY Move cursor to absolute coordinates.
InsChar Insert blank at cursor, push line right.
InsLine Insert line in front of cursor, push
lines down.
Normal Switch to normal text attributes.
Reverse Switch to reversed text attributes.
ScrlDn Scroll screen down a line, insert blank
line at top.
ScrlUp Scroll screen up a line, insert blank
line at bottom.
This record exists is each of the virtual console objects.
To get a command, you should use the EmuXXX methods instead of
directly accessing this record structure.
See Also: EmuXXX methods.
TextBackground
Declaration: PROCEDURE TextBackground(Color: Byte);
Sets the background color used when writing characters to
the display. This value can range from 0 to 7. You can OR this
value with the Blink constant to force the text to blink on and
off.
See Also: GetTextBackground, TextColor.
TextColor
Declaration: PROCEDURE TextColor(Color: Byte);
Sets the foreground color for text written to the console's
display. This value can range from 0 to 15, or you can use the
constants provided in the VC unit. If you want blinking
characters, you can set them by ORing the color byte with the
Blink constant.
See Also: GetTextColor, TextBackground.
TextMode
Declaration: PROCEDURE TextMode(ToMode: Integer);
Switches the console text mode somewhat like the CRT unit's
procedure by the same name. The only restriction placed on the
virtual console is that the width of the display must always be
80. This basically means you cannot change the mode on the CGA,
and can choose between 80x25 and 80x43 on the EGA, and 80x25 or
80x50 on the VGA.
See Also: LastMode variable.
TranslateString
Declaration: PROCEDURE TranslateString;
Tries to translate the current filter information into a
legal emulation sequence. If it can, it will go and perform
whatever action is defined for the code(s) in the string.
Otherwise it will send the text to the console.
See Also: ValidString.
TStaticCollection type
Declaration: TStaticCollection = object(TCollection)
TStaticCollection is a descendent form of the TCollection
object provided in the Objects unit of Turbo Pascal versions 6.0
and newer. TCollection is a dynamic array which allows the
programming to add variables of any type and size to an array
which will grow or shrink according to its elements.
Ordinarily, TCollection will compress the elements of the
collection after a item is removed from the collection.
TStaticCollection alters this behavior to not compress the
elements of the collection, but to rather just store a nil
pointer at that index. Additionally, TCollection.Insert will
simply insert the new item at the end of the collection, while
TStaticCollection first searches for an empty (nil) slot and will
place the new item there is one is found. TStaticCollection
modifies the Done, AtDelete and Insert methods.
TStaticCollection is used by the VC unit to keep an internal
list of the active virtual consoles and the pointers to their
objects.
See Also: Objects.TCollection.
TValidStr type
Declaration: TValidStr = (Yes, No, Maybe);
This enumerated type is used by the ValidString method to
return the status of a possible emulation code.
See Also: ValidString.
TVirtualConsole variables
Declaration: Var
ANSI : Boolean;
Emu : TEmulation;
FilterStr : String[80];
LastMode : Integer;
TextAttr : Byte;
WindMax : Word;
WindMin : Word;
WinList : TCollection;
t
the TVirtualConsole object. They may be accessed in descendant
objects as well, just be careful!
ANSI True if the current emulation template is ANSI-
style.
Emu Emulation template record.
FilterStr Contains the current possible emulation code.
LastMode Last text mode that the console was in.
TextAttr Current text attribute byte.
WindMax Current window maximum coordinates.
WindMin Current window minimum coordinates.
WinList TCollection of the active windows on-screen.
WindMax and WindMin are constructed exactly like they are in
the CRT unit; check your manuals for more information on how
these variables are used.
These variables are, for the most part, volatile. Don't
change their values unless you are indirectly doing it through
one of the virtual console methods, or bad things will start
happening to your video display (the text screen, that is).
See Also: CRT.WindMax, CRT.WindMin.
TWindow type
Declaration: TWindow = record
X1, Y1 : Byte;
Width, Height: Byte;
Border : TBorder;
TextMem : Pointer;
WMin, WMax : Word;
OldColors : Byte;
OldX, OldY : Byte;
Title : String;
end;
These variables keep track of an active window on a virtual
console, if any. The entire screen does not count as an active
window. Windows are created with the OpenWindow method and
removed using the CloseWindow method.
See Also: CloseWindow, OpenWindow, SetWindowTitle.
ValidString
Declaration: FUNCTION ValidString: TValidStr;
Returns Yes, No or Maybe, depending on the filter string
currently in memory. If the filter string is a valid emulation
code (and only one), it will return Yes. If there is any
possibility that the code is part of what would be a legal
emulation string, it will return Maybe. Otherwise it will return
No.
See Also: TranslateString, TValidStr.
vcReadLn
Declaration: PROCEDURE vcReadLn(var Strn: String);
Reads a line of text from the console. Note that this
version is more restricted than the version provided with the CRT
unit. It will only read strings of text and can only read from
the local console. If you need to read from a file, you should
use the CRT unit's ReadLn procedure. It is for this reason that
this method was prefixed with a "vc" in it's name.
See Also: CRT.ReadLn, ReadKey.
vcWrite
Declaration: PROCEDURE vcWrite(Strn: String);
Writes a string of text to the virtual console. Does not
filter it through the emulation template; if you need this
functionality use the FilterWrite and FilterWriteLn methods. The
only other restrictions are that it can only handle strings, and
it cannot send text to any device except the console. If you
need to write variables to a file, use the CRT unit's Write or
WriteLn procedures instead.
See Also: FilterWrite, FilterWriteLn, vcWriteLn.
vcWriteLn
Declaration: PROCEDURE vcWriteLn(Strn: String);
Writes a string of text to the console, ending by placing
the cursor in the first column of the next row and scrolling the
screen if necessary. Does not filter through the emulation
template; use FilterWriteLn if you need this functionality.
See Also: FilterWriteLn, vcWrite.
WhereX
Declaration: FUNCTION WhereX: Byte;
Returns the current X coordinate, relative to the current
window. The left edge is defined as column 1.
See Also: GotoXY, WhereY.
WhereY
Declaration: FUNCTION WhereY: Byte;
Returns the current Y coordinate, relative to the current
window. The top edge is defined as row 1.
See Also: GotoXY, WhereX.
Window
Declaration: PROCEDURE Window(X1, Y1, X2, Y2: Byte);
Defines a window on the screen for the console. This new
window will be the only area of the screen which can be written
to, until Window is called again with new coordinates. To set
the window back to use the whole screen, use Window(1, 1,
Lo(WindMax) + 1, Hi(WindMax) + 1).
See Also: OpenWindow.
WindowHeight
Declaration: FUNCTION WindowHeight: Byte;
Returns the height of the current text window opened using
either the Window or OpenWindow methods.
See Also: WindowWidth.
WindowWidth
Declaration: FUNCTION WindowWidth: Byte;
Returns the width of the current text window opened using
either the Window or OpenWindow methods.
See Also: WindowHeight.
Chapter 9: Procedure/Function Reference
AltDown Util
Declaration: FUNCTION AltDown: Boolean;
Returns True if either of the alt keys is being held down at
the time of the call.
See Also: LeftAltDown, RightAltDown.
Backspace Util
Declaration: FUNCTION Backspace(Num: Byte): String;
Returns Num backspace characters (#8) in string form.
See Also: Replicate.
BitIsSet Util
Declaration: FUNCTION BitIsSet(Value, Bit: Byte): Boolean;
Returns True if a bit is set in the byte Value passed to the
function. Bit must be a number between 0 and 7, inclusive. A 0
corresponds to the least significant bit in the 8-bit value, a 7
is the most significant bit.
See Also: ClearBit, SetBit.
BpsRate Comm
Declaration: FUNCTION BpsRate(PortIdx: Byte): Longint;
Returns the current bits per second (bps) rate of the
specified COM port. Sometimes the bps rate is referred to as the
baud rate.
See Also: SetBpsRate.
Button type Mouse
Declaration: Button = (NoB, LeftB, RightB, BothB);
Button status type for calls to the mouse interface unit.
See Also:
CapsLock Util
Declaration: FUNCTION CapsLock: Boolean;
Returns True if caps lock is enabled.
See Also: NumLock, ScrollLock.
Carrier Comm
Declaration: FUNCTION Carrier(PortIdx: Byte): Boolean;
Returns True if a carrier exists on the specified COM port,
False otherwise.
See Also: ModemError, ErrXXX constants.
Center Util
Declaration: FUNCTION Center(Strn: String): String;
Returns a string which would be Strn centered the current
text window. Note that this only works for the CRT text window,
and not text windows on a virtual console. This is accomplished
using space padding on the left of the string. The string is not
stripped of whitespace before being padded.
See Also: Left, Right.
ClearBit Util
Declaration: PROCEDURE ClearBit(var Value: Byte; Bit:
Byte);
Clears a bit in the byte Value. Bit must be a number
between 0 and 7, inclusive, where 0 signifies the least
significant bit and 7 the most significant bit.
See Also: BitIsSet, SetBit.
ClearPort Comm
Declaration: PROCEDURE ClearPort(PortIdx: Byte);
Attempts to clear the COM port by reading and clearing some
of the UART registers. Specifically it reads RBR, LSR and MSR,
and toggles the IER in case interrupts have somehow to been lost.
See Also: UART constants.
ClearReceiveBuffer Comm
Declaration: PROCEDURE ClearReceiveBuffer(PortIdx: Byte);
Empties the receive buffer of any waiting characters.
See Also: ClearSendBuffer.
ClearSendBuffer Comm
Declaration: PROCEDURE ClearSendBuffer(PortIdx: Byte);
Empties the send buffer of any unsent characters.
See Also: ClearReceiveBuffer, FlushSendBuffer.
ClearToSend Comm
Declaration: FUNCTION ClearToSend(PortIdx: Byte): Boolean;
Returns the status of the clear to send (CTS) bit in the
modem status register. This is used for hardware handshaking.
If True, it means that the remote modem is ready to accept
incoming characters (your modem is clear to send). If False, the
remote modem is not ready and characters should not be sent until
the bit is toggled.
See Also: SetRTS.
Color variable Util
Declaration: Color: Boolean;
This variable is set at program startup. It is True if a
color display is in use, False for monochrome.
See Also: VSeg.
CommandLine Util
Declaration: FUNCTION CommandLine(Strn: String): Boolean;
Returns True if the literal string Strn exists in the
command line in its entirety. This means that you must be
looking for an exact match, not a partial match.
See Also: CommandLineValue, InCommandLine.
CommandLineValue Util
Declaration: FUNCTION CommandLineValue(Strn: String):
String;
o
of the text coming after /H= in the command line. It will match
the first parameter it finds and return that string only.
See Also: CommandLine, InCommandLine.
ConfineMouseX Mouse
Declaration: PROCEDURE ConfineMouseX(Left, Right:
Integer);
Restricts mouse movement to a region bound on the left and
right. You should call this procedure (or ConfineScreen) after
any mode changes to assure that the mouse has full run of the
screen. Alternatively, you can restrict mouse movement to a
small region of the screen where you wish the user to be able to
move the cursor.
See Also: ConfineMouseY, ConfineScreen.
ConfineMouseY Mouse
Declaration: PROCEDURE ConfineMouseY(Top, Bot: Integer);
Restricts mouse movement to a region bound on the top and
bottom. You should call this procedure (or ConfineScreen) after
any mode changes to assure that the mouse has full run of the
screen. Alternatively, you can restrict mouse movement to a
small region of the screen where you wish the user to be able to
move the cursor.
See Also: ConfineMouseX, ConfineScreen.
ConfineScreen Mouse
Declaration: PROCEDURE ConfineScreen;
Confines the mouse cursor to the entire screen of the
current video mode. This assures that the mouse is able to move
over the whole screen, without disappearing off the edges.
See Also: ConfineMouseX, ConfineMouseY.
ControlDown Util
Declaration: FUNCTION ControlDown: Boolean;
Returns True if either control key is being held down when
the function is called.
See Also: LeftControlDown, RightControlDown.
CopyFile Util
Declaration: FUNCTION CopyFile(Source, Dest: String):
Boolean;
Copies a file from the source to either a destination file
or destination directory. If you specify a destination
directory, the filename used for the copy will be the same as the
source. If this file exists in the destination directory
already, CopyFile will return a False value.
Otherwise, if you tell it a specific file to copy to, it
will overwrite it if it already exists.
CopyFile will return True if there were no errors during the
copy, False otherwise. A False value generally means that there
was some problem with disk I/O.
See Also:
CountryInfo variable Util
Declaration: CountryInfo: TCountryInfo;
This variable is set to the local country values at program
startup by calling GetCountryInfo(CountryInfo). If you only wish
to check the local information quickly, there is no need to call
GetCountryInfo and go through a slow DOS interrupt.
See Also: GetCountryInfo, TCountryInfo record.
CPU variable Util
Declaration: CPU: Byte;
Contains the value returned by Processor for the current
machine. This variable is set at program startup.
See Also: Processor, Test8086.
DataTerminalReady Comm
Declaration: FUNCTION DataTerminalReady(PortIdx: Byte):
Boolean;
Returns the status of the DTR bit in the modem control
register. Most modems will not accept commands or send & receive
characters if the DTR bit is not set. Additionally, some modems
will interpret a low DTR line as a request to put the modem on-
hook (hung up).
See Also: SetDTR.
Date Util
Declaration: FUNCTION Date: String;
Returns the date in a nicely formatted way, paying attention
to country information if it exists when DOS is queried for it.
Country information affects the order in which the date is
presented. Programs run in the USA will return MM/DD/YY, when
run in Europe it will return DD/MM/YY, and when run in Japan it
will return YY/MM/DD. The date separator also varies depending
on the country information. You can change country info using
COUNTRY.SYS if needed.
See Also: Time.
DeInitPort Comm
Declaration: PROCEDURE DeInitPort(PortIdx: Byte);
Shuts the COM port down. Removes all the interrupt hooks
from the interrupt vector, disables interrupts on that COM port,
frees the memory taken up by the send and receive buffers, and
exits. The port will no longer be serviced by the comm routines.
See Also: InitPort.
DetectPort Comm
Declaration: FUNCTION DetectPort(PortIdx: Byte): Boolean;
Attempts to detect whether or not a National-based UART
exists at the specified COM port. It will run the standard
loopback test on the COM port and, if successful, will return a
True value. If a valid National-based UART cannot be found, it
will return False.
Note that more and more internal modem manufacturers are
using a UART chip that does not appear to be 100% compatible with
the National 8250B, and will fail this test even though the UART
works in all other respects.
See Also: DetectUART.
DetectUART Comm
Declaration: FUNCTION DetectUART(PortIdx: Byte): String;
Attempts to detect which National-based UART exists at the
specified port. It is assumed at the top of this procedure that
a UART does exist at the COM port, so no checking is done in this
respect. If you are not sure of the existence of a COM port, use
DetectPort first.
DetectUART will return a string describing the type of UART
found at the COM port:
8250B National 8250B or compatible (no scratch register,
no FIFOs).
16450 National 16450 or compatible (scratch register, no
FIFOs).
16550 National 16550 or compatible (scratch register, no
working FIFOs).
16550A National 16550A or compatible (scratch register,
working FIFOs).
Please note that the original National 16550 UART found in
early IBM PS/2's did not have working FIFO buffers for send or
receive, and subsequently should be treated as a National 16450
UART.
See Also: DetectPort.
ErrXXX constants Comm
Declaration: (in Const block)
These constants are used to check the error flag for any of
the comports. To get the error flag, use the ModemError function
and these constants to mask out the different events.
ErrInputOverflow = $01 Signals that the receive buffer was
full when another character came
in.
ErrOutputOverflow = $02 Signals that the send buffer was
full when you tried to send another
character out.
ErrInactivity = $04 Signals that the user was inactive
for an extended period of time.
ErrOverrun = $08 An overrun error occurred at the
UART. This means that before a
character was fetched from the
receive buffer register, another
character was ready to be stored
there.
ErrParity = $10 The UART detected a parity error on
the incoming byte.
ErrFraming = $20 The UART detected a framing error
on the incoming byte.
ErrCarrierLost = $40 Carrier no longer exists when it
once did. Useful for catching
people who hang up on the system.
ErrBreakSignal = $80 The UART detected a break signal.
See Also: ModemError.
Exist Util
Declaration: FUNCTION Exist(Filename: String): Boolean;
Returns True if the file exists, False if it doesn't.
See Also:
FillWord Util
Declaration: PROCEDURE FillWord(Dest: Pointer; Value, Len:
Word);
Fills a block of memory Len bytes long with the word in
Value. This performs the same operation as FillChar does, but
moves twice as much information in the same space of time.
See Also: System.FillChar.
FlushSendBuffer Comm
Declaration: PROCEDURE FlushSendBuffer(PortIdx: Byte);
Repeatedly loops until it sees that all of the characters
waiting in the send buffer have been sent out the UART, and
returns. Note that this is different that calling
ClearSendBuffer because the characters are given a chance to be
sent, and are not thrown away instead.
See Also: ClearSendBuffer.
GetCountryInfo Util
Declaration: PROCEDURE GetCountryInfo(var InfoRec:
TCountryInfo);
Retrieves country information from DOS. This procedure
requires the use of DOS 3.3 or newer.
See Also: CountryInfo variable, TCountryInfo record.
GetDirectory Util
Declaration: FUNCTION GetDirectory(Str: String): DirStr;
Strips the directory out of a fully qualified pathname and
returns it.
See Also: GetExtension, GetFilename.
GetExtension Util
Declaration: FUNCTION GetExtension(Str: String): ExtStr;
Strips the extension out of a filename and returns it.
There is a preceding period (.) before the actual three-letter
extension.
See Also: GetDirectory, GetFilename.
GetFilename Util
Declaration: FUNCTION GetFilename(Str: String): NameStr;
Strips the name out of a filename and returns it. This is
the 8-letter portion of the filename, without the extension.
See Also: GetDirectory, GetExtension.
GetFlowControl Comm
Declaration: PROCEDURE GetFlowControl(PortIdx: Byte; var
XonXoff, RTSCTS: Boolean);
Gets the current flow control settings for the COM port.
XonXoff and RTSCTS are boolean variables which return the status
of that type of handshaking.
XonXoff is software handshaking and requires the use of two
characters for starting/stopping the flow of data. Typically ^S
is used to stop the flow, and ^Q is used to restart it. RTSCTS
uses two hardware lines for flow control, and is transparent to
the entire 8-bit character set.
See Also: SetFlowControl.
GetMouseAction Mouse
Declaration: PROCEDURE GetMouseAction(var But: Button; var
X, Y: Integer);
Returns the current status of the mouse. But contains the
button status, X contains the X coordinate of the mouse cursor,
and Y contains the Y coordinate of the mouse cursor.
See Also: MoveMouse.
GetScreenWord Util
Declaration: PROCEDURE GetScreenWord(X, Y: Byte; var Ch:
Char; var Attr: Byte);
Gets the word which defines the character and color
attribute for the cell at (X, Y). These are absolute
coordinates, and are not relative to the current window on-
screen. On return, Ch will contain the character at that cell,
and Attr will contain the attribute byte.
See Also: PutScreenWord, GetText.
GetText Util
Declaration: PROCEDURE GetText(X1, Y1, X2, Y2: Byte; Dest:
Pointer);
Gets a block of text data from the console's video memory
and places it in memory pointed to by Dest. The memory must have
been allocated before the call to GetText. You can figure out
the proper size for a given rectangle of text using either the
TextMemSize function, or by using this formula:
[(X2 - X1) + 1] * [(Y2 - Y1) + 1] + 2
See Also: GetScreenWord, PutText.
HexByte Util
Declaration: FUNCTION HexByte(Num: Byte): String;
Returns the two character hexadecimal value of Num.
See Also: HexLongint, HexWord.
HexLongint Util
Declaration: FUNCTION HexLongint(Num: Longint): String;
Returns the eight character hexadecimal value of Num.
See Also: HexByte, HexWord.
HexWord Util
Declaration: FUNCTION HexWord(Num: Word): String;
Returns the four character hexadecimal value of Num.
See Also: HexByte, HexLongint.
HideMouseCursor Mouse
Declaration: PROCEDURE HideMouseCursor;
Hides the mouse cursor if it isn't already hidden.
See Also: ShowMouseCursor.
HideTextCursor Util
Declaration: PROCEDURE HideTextCursor;
Hides the text cursor on the local screen.
See Also: ShowTextCursor.
HighNybble Util
Declaration: FUNCTION HighNybble(A: Byte): Byte;
Returns the high 4 bits of a byte value. Example:
HighNybble($AB) returns $A.
See Also: LowNybble.
InCommandLine Util
Declaration: FUNCTION InCommandLine(Strn: String): Byte;
Searches for the first substring match of Strn within the
command line. If it can find a substring match, it will return
the index into the command line in which the first match occurs.
If no match can be found, it returns 0. For example, if you run
the command TEST COMMAND.COM and call InCommandLine(".COM"), it
will return 1.
See Also: CommandLine, CommandLineValue.
InitPort Comm
Declaration: FUNCTION InitPort(PortIdx: Byte; BufferSize:
Word);
Initializes a port for use by the comm routines. This must
be called before any other action is taken on a COM port. Please
note that the PortIdx variable is not an index to the absolute
COM ports provided on the IBM and compatibles, but rather is an
index into the PortArray variable kept by the Comm unit. Default
settings start things up so that COM1 is indexed as port 1, COM2
as port 2, COM3 as port 3, and COM4 as port 4. Ports 5 through 8
are undefined in the default distribution and are intended for
use by non-standard ports or multiport hardware.
BufferSize is the size of the send and receive buffers, in
bytes. InitPort will return a True value if things went okay and
the port is initialized, and False if there was a problem such as
insufficient memory for the buffers or an index out of the range
1..NumPorts.
See Also: DeInitPort.
InsertOn Util
Declaration: FUNCTION InsertOn: Boolean;
Returns True if the keyboard is set up for insert mode, or
False if set up for overstrike mode. This value is grabbed from
the BIOS data area, segment $40.
See Also:
IntToStr Util
Declaration: FUNCTION IntToStr(Num: Longint): String;
Converts a numeric integer value into its string
representation. This function performs the same task that the
Str system procedure does, but in a function form.
See Also: StrToInt.
Left Util
Declaration: FUNCTION Left(Strn: String; Places: Byte):
String;
Left justifies a string of text to a length of Places bytes
by padding on the right side of the string. If the string
exceeds the desired length, it is truncated on the right.
See Also: Center, Right.
LeftAltDown Util
Declaration: FUNCTION LeftAltDown: Boolean;
Returns True if the left alt key is being held down.
See Also: AltDown, RightAltDown.
LeftControlDown Util
Declaration: FUNCTION LeftControlDown: Boolean;
Returns True if the left control key is being held down.
See Also: ControlDown, RightControlDown.
LeftShiftDown Util
Declaration: FUNCTION LeftShiftDown: Boolean;
Returns True if the left shift key is being held down.
See Also: RightShiftDown, ShiftDown.
LineRinging Comm
Declaration: FUNCTION LineRinging(PortIdx: Byte): Boolean;
Returns the status of the ring indicator bit in the modem
status register. Returns True if the bit is set, signaling that
the phone line is ringing. False indicates that a ring is not
occurring now, but does not mean that there isn't a call to be
answered.
See Also: WaitForRingTrailer.
LoCase Util
Declaration: FUNCTION LoCase(Ch: Char): Char;
Converts all uppercase characters ('A'..'Z') to their
lowercase equivalent.
See Also: System.UpCase.
Lower Util
Declaration: FUNCTION Lower(Strn: String): String;
Converts all uppercase characters in a string to lowercase.
All other characters are unaffected.
See Also: Upper.
LowNybble Util
Declaration: FUNCTION LowNybble(A: Byte): Byte;
Returns the lower 4 bits of a byte. Example:
LowNybble($AB) returns $B.
See Also: HighNybble.
ModemError Comm
Declaration: FUNCTION ModemError(PortIdx: Byte): Byte;
Returns the internal error flag byte kept for the COM port.
You can use the ErrXXX bit masks to extract information on error
conditions from this function. Note that once the function is
called, the flags byte is reset to zero internally. If you wish
to repeatedly test the returned byte, you will need to store it
in a new byte variable.
See Also: ErrXXX constants.
Moused variable Mouse
Declaration: Moused: Boolean;
Initialized at program startup. If a mouse is found, this
variable will be set to True.
See Also: MouseInstalled.
MouseInstalled Mouse
Declaration: FUNCTION MouseInstalled: Boolean;
Checks to see if a mouse driver is installed at interrupt
$33. If one is found, it will return True.
See Also: Moused variable.
MousePressed Mouse
Declaration: FUNCTION MousePressed(Button: Integer):
Boolean;
Returns the status of the specified mouse button being
depressed. In general, a 0 is the left button, and a 1 is the
right button.
See Also: MouseReleased.
MouseReleased Mouse
Declaration: FUNCTION MouseReleased(Button: Integer):
Boolean;
Returns the status of the specified mouse button being
released. In general, a 0 is the left button, and a 1 is the
right button.
See Also: MousePressed.
MoveMouse Mouse
Declaration: PROCEDURE MoveMouse(X, Y: Integer);
Moves the mouse cursor to the (X,Y) on-screen.
Automatically does the conversion between graphics and text
modes, so this coordinate will be the same as the native mode
coordinate.
See Also: GetMouseAction.
MoveWord Util
Declaration: PROCEDURE MoveWord(Source, Dest: Pointer;
Length: Word);
Moves Length bytes from Source to Dest. This procedure
moves information twice as fast as the system Move procedure
since it moves whole words at a time instead of bytes. Length
should be an even number or the procedure will choke.
See Also: System.Move.
NumLock Util
Declaration: FUNCTION NumLock: Boolean;
Returns True if num lock is enabled.
See Also: CapsLock, ScrollLock.
NumPorts constant Comm
Declaration: NumPorts = 8;
This constant controls the number of concurrent ports
supported by BBSkit. If you change this number to anything
higher than 8, you must make sure to go into the code and create
interrupt services for the new ports. This will entail editing
both COMM.PAS and BBSCOMM.ASM. You may decrease this value
without affecting the operation of the Comm unit.
See Also: PortArray variable.
OCW constants Comm
Declaration: (in Const block)
These constants are used to point at two ports in every IBM
compatible computer, the Operation Control Words. These two
bytes control the 8259 Programmable Interrupt Chip and allow
BBSkit to receive comm interrupts from the comports in use.
OCW1 = $21 Operation control word 1; controls what
interrupts are serviced.
OCW2 = $20 Operation control word 2; controls End Of
Interrupt codes.
See Also: UART constants.
Parity Comm
Declaration: FUNCTION Parity(PortIdx: Byte): TParity;
Returns the parity set for the COM port. It can be one of
NoParity, OddParity, EvenParity, MarkParity or SpaceParity.
See Also: SetParity, TParity type.
PeekKeyboard Util
Declaration: FUNCTION PeekKeyboard: Char;
Peeks at the keyboard buffer and returns the next waiting
character, if any, without actually removing it from the buffer.
See Also:
PeekNextChar Comm
Declaration: FUNCTION PeekNextChar(PortIdx: Byte): Char;
Returns the next available character in the receive buffer
without actually removing it from the buffer. If there are no
characters waiting in the buffer, this function will return an
undefined character.
See Also: ReceiveBufferEmpty, Receive, ReceiveW.
PortArray variable Comm
Declaration: PortArray : Array[1..NumPorts] of TPortCfg;
Defines an array which holds all of the information on the
COM ports usable by the communications routines.
See Also: NumPorts constant.
Processor Util
Declaration: FUNCTION Processor: Integer;
Returns the processor type determined by running a couple of
checks. The value returned will be one of the following and
corresponds to a different member of the 80x86 family:
0 = Intel 8088 (or compatible chip)
1 = Intel 8086 (or compatible chip)
2 = Intel 80286 (or compatible chip)
3 = Intel 80386 (or compatible chip)
4 = Intel 80486+ (or compatible chip)
See Also: System.Test8086 variable (BP7+).
ProgramName Util
Declaration: FUNCTION ProgramName: NameStr;
Returns the name of the program running. This is fetched
from the command line (the program name is in ParamStr(0)).
See Also: GetFilename.
PutScreenWord Util
Declaration: PROCEDURE PutScreenWord(X, Y: Byte; Ch: Char;
Attr: Byte);
Puts a character and attribute combination directly into the
console's video memory at the character cell defined by (X,Y).
This coordinate is absolute and is not affected by any active
windows.
See Also: GetScreenWord, PutText.
PutText Util
Declaration: PROCEDURE PutText(X, Y: Byte; Source:
Pointer);
Puts a block of text previously saved with a call to GetText
directly into the console's video memory. The upper left corner
of the block is defined by (X,Y). This coordinate is absolute
and is not affected by any active windows.
See Also: GetText, PutScreenWord.
Receive Comm
Declaration: FUNCTION Receive(PortIdx: Byte): Char;
Returns the next character from the receive buffer. If
there are no character waiting in the buffer, it will not wait
but will rather return an undefined character.
See Also: PeekNextChar, ReceiveW.
ReceiveBlock Comm
Declaration: PROCEDURE ReceiveBlock(PortIdx: Byte; Block:
Pointer; Len: Word);
Receives a block of characters of length Len from the COM
port. This is much more efficient than repeatedly calling
ReceiveW if you are expecting large blocks of data.
ReceiveBlock will wait patiently for enough characters to
appear before it returns.
See Also: ReceiveW, SendBlock.
ReceiveBufferEmpty Comm
Declaration: FUNCTION ReceiveBufferEmpty(PortIdx: Byte):
Boolean;
Returns True if there are no characters waiting in the
receive buffer, False otherwise. Use this function to check and
see if there are any waiting characters before calling
PeekNextChar or Receive to avoid getting garbage characters.
See Also: ReceiveBufferFull.
ReceiveBufferFull Comm
Declaration: FUNCTION ReceiveBufferFull(PortIdx: Byte):
Boolean;
Returns True if there is no room remaining in the receive
buffer, False otherwise. If this function returns True and
another characters needs to be put in the buffer before any are
removed, an overflow error will result on the receive buffer.
See Also: ReceiveBufferEmpty.
ReceiveW Comm
Declaration: FUNCTION ReceiveW(PortIdx: Byte): Char;
Waits for a character to appear in the receive buffer before
fetching and returning it. This is the function which will be
most used in your applications since it will never return garbage
characters. To avoid getting stuck in a loop you should still
call ReceiveBufferEmpty before calling this function, however.
See Also: Receive, ReceiveBufferEmpty.
Replicate Util
Declaration: FUNCTION Replicate(Ch: String; Num: Byte):
String;
Repeats a string of characters Num times and returns the
resulting string. It is up to the programmer to make sure that
the resulting string does not exceed 255 characters.
See Also: Space.
RestoreScreen Util
Declaration: PROCEDURE RestoreScreen;
Restores the screen to a previous state after a call to
SaveScreen. You can use these procedures in combination to
restore the screen after running a program. Put a call to
SaveScreen at the beginning of your program before you send any
output to the screen, and call RestoreScreen right before you
exit to DOS to restore the user's screen before quitting.
Restoring a screen not previously saved will give unpredictable
results.
See Also: SaveScreen.
Right Util
Declaration: FUNCTION Right(Strn: String; Places: Byte):
String;
Right justifies a string by padding the left edge with
spaces until the length of the string is equal to Places. If the
string was too long to begin with, it will be truncated on the
left edge.
See Also: Center, Left.
RightAltDown Util
Declaration: FUNCTION RightAltDown: Boolean;
Returns True if the right alt key is being held down.
See Also: AltDown, LeftAltDown.
RightControlDown Util
Declaration: FUNCTION RightControlDown: Boolean;
Returns True if the right control key is being held down.
See Also: ControlDown, LeftControlDown.
RightShiftDown Util
Declaration: FUNCTION RightShiftDown: Boolean;
Returns True if the right shift key is being held down.
See Also: LeftShiftDown, ShiftDown.
RootDir Util
Declaration: FUNCTION RootDir: DirStr;
Returns the root directory from which the program was run.
This can be especially useful for storing files in one standard
directory on disk. The pathname will always end in a backslash
(\).
See Also: GetPathname.
SaveScreen Util
Declaration: PROCEDURE SaveScreen;
Saves the screen and cursor position for later restoration
using RestoreScreen. If you call this procedure more than once,
only the most recent save will be kept.
See Also: RestoreScreen.
ScrollLock Util
Declaration: FUNCTION ScrollLock: Boolean;
Returns True if scroll lock is enabled.
See Also: CapsLock, NumLock.
Segment constants Util
Declaration: Const
Seg0040 : Word = $40;
SegA000 : Word = $A000;
SegB000 : Word = $B000;
SegB800 : Word = $B800;
These constants are deleted to keep the source compatible
with Turbo Pascal 6.0. When compiling under 7.0, this block is
not included since the constants are already defined. They are
provided for compatibility with programs compiled for DPMI. You
should make it a habit to use these segment constants instead of
the literal values since under DPMI their values may change.
See Also:
Send Comm
Declaration: PROCEDURE Send(PortIdx: Byte; Ch: Char);
Sends a single character out the COM port by placing it in
the send buffer. If there is not enough room in the buffer for
this character, the overflow bit will be set in the error flag
and the character will not be sent. If you wish to use some
error checking and not lose characters, you should probably use
SendW.
See Also: SendBlock, SendW.
SendBlock Comm
Declaration: PROCEDURE SendBlock(PortIdx: Byte; Block:
Pointer; Len: Word);
Sends a block of data out the COM port by placing it in the
send buffer in one quick move instead of repeatedly calling
SendW. This is much more efficient.
SendBlock will patiently wait for enough room to be in the
buffer before starting the move.
See Also: Send, SendW.
SendBreak Comm
Declaration: PROCEDURE SendBreak(PortIdx: Byte);
Sends a 230ms break signal across the line. Some systems
(including these comm routines) are smart enough to give a break
signal special handling.
See Also: ErrXXX constants, ModemError.
SendBufferEmpty Comm
Declaration: FUNCTION SendBufferEmpty(PortIdx: Byte):
Boolean;
Returns True if the send buffer for the COM port is empty.
Otherwise it returns False.
See Also: SendBufferFull.
SendBufferFull Comm
Declaration: FUNCTION SendBufferFull(PortIdx: Byte):
Boolean;
Returns True if the send buffer is completely filled and
there is no room for any additional characters, False otherwise.
See Also: SendBufferEmpty.
SendString Comm
Declaration: PROCEDURE SendString(PortIdx: Byte; Strn:
String);
Sends an entire string out the COM port by placing the
characters in the send buffer. This procedure does pay attention
to the buffer size and will wait for room if there isn't enough
at first. Actually equivalent to calling SendBlock(PortIdx,
@Strn[1], Length(Strn)).
See Also: SendBlock.
SendW Comm
Declaration: PROCEDURE SendW(PortIdx: Byte; Ch: Char);
Places a character in the send buffer, after first making
sure there is room. If there isn't, it will wait until there and
then place the character.
See Also: Send, SendBlock.
SetBBSMode Comm
Declaration: PROCEDURE SetBBSMode(PortIdx: Byte; Status:
Boolean);
Either enables or disables the BBS mode depending on the
argument passed in Status. When True, the comm routines will pay
attention to user inactivity during handshaking and will allow
the remote user to clear the receive buffer using either a break
signal or a special control character.
When disabled, the comm routines won't watch user
inactivity, and won't translate break signals or a clear
character.
See Also: ErrXXX constants, ModemError.
SetBit Util
Declaration: PROCEDURE SetBit(var Value: Byte; Bit: Byte);
Sets a bit in the Value byte. Bit must be a value between 0
and 7, inclusive. A 0 corresponds to the least significant bit,
while 7 to the most significant.
See Also: BitIsSet, ClearBit.
SetBpsRate Comm
Declaration: PROCEDURE SetBpsRate(PortIdx: Byte; Bps:
Longint);
Sets the bits per second (bps) rate of the COM port. It
does this by computing a divisor value based on the bps rate
which will fit into a 16-bit value, and placing the two bytes in
the UART registers.
See Also: BpsRate.
SetBreakClearBuffer Comm
Declaration: PROCEDURE SetBreakClearBuffer(PortIdx: Byte;
Status; Boolean);
When BBS mode is turned on with a call to SetBBSMode, a
break signal sent by the remote user is capable of clearing the
receive buffer on the local machine. This procedure sets whether
or not you want the break signal to clear the buffer or to set a
bit in the ErrorFlg variable to be handled by your own code.
Clearing the receive buffer can be useful for users when they
have sent a command that they no longer want processed by the
system.
See Also: SetBBSMode, SetClearBufferChar.
SetClearBufferChar Comm
Declaration: PROCEDURE SetClearBufferChar(PortIdx: Byte;
Ch: Char);
When BBS mode is enabled, the internal routines are capable
of clearing the local receive buffer when a predefined character
is received. Typically this character is a non-displayable
control character, and is defined with this procedure. When the
remote user sends this character, the receive buffer will be
emptied before it can be processed. This can be useful for
clearing a command which has already been sent in error.
See Also: SetBreakClearBuffer.
SetDTR Comm
Declaration: PROCEDURE SetDTR(PortIdx: Byte; Status:
Boolean);
Sets the Data Terminal Ready bit in the modem control
register. Most modems will not accept commands or send & receive
data until the DTR bit is set high (True). Additionally, a low
DTR bit will often signal a modem to hang up the phone and break
any existing connection. Generally, you'll want to set this to
True before doing any I/O work with your COM port.
See Also: DataTerminalReady.
SetFIFO Comm
Declaration: PROCEDURE SetFIFO(PortIdx: Byte; Status:
Boolean);
This procedure controls the use of the FIFO (first-in, first-
out) buffers found on the National 16550A UART. The FIFO buffers
are useful for high-speed connections because they can buffer
data if the CPU is not fast enough to process it as it comes in.
This procedure simply enables or disables the FIFOs. If you want
to specify the depth of the FIFO buffers (1, 4, 8 or 14
characters) you can do that using the SetFIFOTrigger procedure.
See Also: SetFIFOTrigger.
SetFIFOTrigger Comm
Declaration: PROCEDURE SetFIFOTrigger(PortIdx, Trigger:
Byte);
Sets the trigger level of the internal FIFO buffers on the
National 16550A UART. The trigger level specifies how many
characters must be in the buffer before the appropriate interrupt
is triggered. The value can be one of 1, 4, 8 or 14 characters.
The interrupt will also be triggered if no additional
activity takes place in the time it takes to receive a character,
in the case of the receive interrupt.
See Also: SetFIFO.
SetFlowControl Comm
Declaration: PROCEDURE SetFlowControl(PortIdx: Byte;
XonXoff, RTSCTS: Boolean);
Sets the flow control styles used by the comm routines.
Usually this will be one or the other, and generally not both.
If True, that style of flow control is enabled. If False, it is
disabled.
XonXoff corresponds to software flow control, which makes
use of two characters from the available character set for flow
control. RTSCTS corresponds to hardware flow control, which uses
hardware lines for flow control, remaining transparent to the
character set.
See Also: GetFlowControl, SetFlowLimits.
SetFlowLimits Comm
Declaration: PROCEDURE SetFlowLimits(PortIdx: Byte; Xon,
Xoff: Word);
Controls the level of the buffers as flow control is enabled
and disabled. Xon and Xoff correspond to the number of
characters left in the buffer as each action occurs.
When the level rises to Xon or higher, flow control is
enabled. Generally this should be about 8 or so characters less
than the size of your buffers. Flow control is disabled when the
level drops equal to or below Xoff.
See Also: SetFlowControl.
SetInactiveLimit Comm
Declaration: PROCEDURE SetInactiveLimit(PortIdx: Byte;
Sec: Word);
Sets the time, in seconds, that a user can leave flow
control enabled without releasing it. This is only watched when
in BBS mode, enabled through a call to SetBBSMode. It is
designed to keep users from tying up your system by enabled flow
control and walking away for excessive periods of time.
See Also: SetBBSMode.
SetMouseCursorStyle Mouse
Declaration: PROCEDURE SetMouseCursorStyle(OrdChar:
Integer);
Defines how the cursor looks in text mode. This procedure
just changes the look of the mouse cursor and the affect it has
on the colors of the screen. The high byte is the color mask,
and the low byte is the ASCII code of the character in the
foreground.
See Also:
SetParity Comm
Declaration: PROCEDURE SetParity(PortIdx: Byte; Mode:
TParity);
Sets the parity style used for the COM port. The five
parity styles can be found by looking under TParity. Generally,
NoParity is used for 8-bit connections, while EvenParity is used
for many 7-bit connections.
See Also: Parity, TParity type.
SetRTS Comm
Declaration: PROCEDURE SetRTS(PortIdx: Byte; Status:
Boolean);
Sets the request to send bit in the modem control register.
This bit is used for hardware flow control and generally
shouldn't be touched except by the internal comm routines.
See Also: ClearToSend.
SetSoftHandshake Comm
Declaration: PROCEDURE SetSoftHandshake(PortIdx: Byte;
Xon, Xoff: Char);
Sets the characters used in software handshaking for start
and stop of transmission. Xon is the character used for
restarting the transmission, while Xoff is the character used for
stopping transmission. Traditionally, these values of been ^S to
stop, and ^Q to restart.
See Also: SetFlowControl.
SetStopBits Comm
Declaration: PROCEDURE SetStopBits(PortIdx: Byte; Bits:
TStopBits);
Controls the number of stop bits used by the UART for
sending & receiving characters. Typically, this value is 1 for
either 7- or 8-bit connections. Legal values are either 1 or 2.
Note that when the word length is set to 5, setting stop bits to
2 actually sends only 1.5.
See Also: StopBits, TStopBits type.
SetWordLength Comm
Declaration: PROCEDURE SetWordLength(PortIdx: Byte;
WordLen: TWordLength);
Sets the word length of characters sent & received by the
UART. Values for this can range from 5 to 8. Typically, this
will be either 7 or 8.
See Also: TWordLength type, WordLength.
ShiftDown Util
Declaration: FUNCTION ShiftDown: Boolean;
Returns True if either shift key is being held down.
See Also: LeftShiftDown, RightShiftDown.
ShowMouseCursor Mouse
Declaration: PROCEDURE ShowMouseCursor;
Shows the mouse cursor if it isn't already visible.
See Also: HideMouseCursor.
ShowTextCursor Util
Declaration: PROCEDURE ShowTextCursor;
Makes the text mode cursor visible by resetting it back to
the video card defaults (a two scanline cursor in the bottom of
the cell).
See Also: HideTextCursor.
SizeCursor Util
Declaration: PROCEDURE SizeCursor(Top, Bottom: Byte);
Defines the beginning and ending scanlines for the text mode
cursor. A solid block cursor would be equivalent to
SizeCursor(0, 14) on EGA/VGA cards.
See Also: HideTextCursor, ShowTextCursor.
Space Util
Declaration: FUNCTION Space(Num: Byte): String;
Returns Num spaces in a string.
See Also: Replicate.
StopBits Comm
Declaration: FUNCTION StopBits(PortIdx: Byte): TStopBits;
Returns the number of stop bits in use on the COM port.
This value will either be 1 or 2.
See Also: SetStopBits, TStopBits type.
StrobeKeyboard Util
Declaration: PROCEDURE StrobeKeyboard;
Removes all waiting keypresses from the keyboard buffer and
exits.
See Also:
StrToInt Util
Declaration: FUNCTION StrToInt(Strn: String): Longint;
Converts a string into its integer representation and
returns the result. StrToInt stops converting when it hits an
illegal character in the string, so the string "123HELLO" will
still return 123 as an answer. If the string cannot be converted
(example "HELLO") then it will return 0.
See Also: IntToStr.
SwapB Util
Declaration: PROCEDURE SwapB(var A: Byte);
Swaps the high and low nybbles in the byte. $AB comes back
as $BA.
See Also: System.Swap.
TCountryInfo record Util
Declaration: TCountryInfo = record
DateFmt : Word;
CurrencySym: Array[1..5] of Char;
ThousandSep: Char;
Res1 : Byte;
DecimalSep : Char;
Res2 : Byte;
DateSep : Char;
Res3 : Byte;
TimeSep : Char;
Res4 : Byte;
CurrencyFmt: Byte;
DigAfterDec: Byte;
TimeFmt : Byte;
CaseMap : Pointer;
DataListSep: Char;
Res5 : Byte;
Res6 : Array[1..10] of Byte;
end;
This record is used by GetCountryInfo procedure. Your
programs can then take advantage of the country info as specified
by DOS. The Util unit already handles this sort of thing in the
Date and Time functions. ResX variables are bytes reserved by
DOS and having no known useful purpose.
See Also: GetCountryInfo.
TCountdownTimer object Util
Declaration: TCountdownTimer = object
TimeLeft: TTime;
SecLeft : Longint;
Timer : TTimer;
PROCEDURE ClearCountdown;
FUNCTION GetSecondsLeft: Longint;
PROCEDURE GetTimeLeft(var TimeRec: TTime);
PROCEDURE SetTimeLeft(TimeRec: TTime);
PROCEDURE StartCountdown;
PROCEDURE StopCountdown;
end;
This object provides a countdown timer, which will start a
certain value, and count down as time passes. It is up to the
programmer to check this object often enough to catch it when it
hits zero seconds remaining.
The methods are explained in more detail below.
ClearCountdown Clears the countdown timer and stops it if it was
running.
GetSecondsLeft Returns the number of seconds left in the
countdown. This value will never drop below zero.
GetTimeLeft Returns the exact amount of time left in a TTime
record, which provides a bit more precision that
GetSecondsLeft.
SetTimeLeft Sets the time that the countdown will start at.
Unless the timer is already running, you will need
to call StartCountdown to begin timing.
StartCountdown Starts the countdown timer.
StopCountdown Stops the countdown timer.
See Also: TTime record, TTimer.
Test8086 Util
Declaration: Test8086: Byte;
Note: this variable is defined in the System unit for Turbo
Pascal 7.0+. This variable is almost exactly like the CPU
variable defined for all versions of TP, but slightly different
in order to match the value returned in the Test8086 variable in
Turbo Pascal 7.0+. It's value corresponds to the following for
processor types:
0 = Intel 8088/8086 (or compatible)
1 = Intel 80286 (or compatible)
2 = Intel 80386 (or compatible)
3 = Intel 80486+ (or compatible)
See Also:
TextMemSize Util
Declaration: FUNCTION TextMemSize(X1, Y1, X2, Y2: Byte):
Word;
Returns the number of bytes needed to store a text block in
memory using GetText. This function returns a value based on
this formula:
[(X2 - X1) + 1] * [(Y2 - Y1) + 1] + 2
See Also: GetText.
TextScreenMaxX Util
Declaration: FUNCTION TextScreenMaxX: Byte;
Returns the width of the text screen, ignoring any active
windows. Usually this value will come back as 80.
See Also: TextScreenMaxY, TextWinMaxX.
TextScreenMaxY Util
Declaration: FUNCTION TextScreenMaxY: Byte;
Returns the height of the text screen, ignoring any active
windows.
See Also: TextScreenMaxX, TextWinMaxY.
TextWinMaxX Util
Declaration: FUNCTION TextWinMaxX: Byte;
Returns the width of the current window defined on-screen.
See Also: TextScreenMaxX, TextWinMaxY.
TextWinMaxY Util
Declaration: FUNCTION TextWinMaxY: Byte;
Returns the height of the current window defined on-screen.
See Also: TextScreenMaxY, TextWinMaxX.
TFarProc type Util
Declaration: TFarProc = PROCEDURE;
Defines a type that represents a procedure. This is used to
pass procedures as parameters to other procedures or functions.
See Also:
Time Util
Declaration: FUNCTION Time: String;
Returns the current system time in a format which follows
the information retrieved from DOS about the local country
formats. Time is returned in 12-hour format, with a trailing 'a'
or 'p' to specify AM or PM.
See Also: Date.
TParity type Comm
Declaration: TParity = (NoParity, OddParity, EvenParity,
MarkParity, SpaceParity);
Enumerated type used in the SetParity procedure. The five
values equate to the five different parity checking schemes used
by 8250B compatible UARTs.
NoParity No parity checking done. This is used for 8-
bit data words.
OddParity Parity set to make the number of 1's in the
word odd.
EvenParity Parity set to make the number of 1's in the
word even.
MarkParity Parity always a 1.
SpaceParity Parity always a 0.
Parity is a fairly weak form of error detection used in 7-
bit connections. The parity bit is always the 8th bit of a word,
and both ends of the connection must be set to the same parity
for it to work at all. When a parity check fails, the UART will
set the parity error bit in the line status register. You can
check for parity errors using the ModemError function and the
ErrParity mask.
See Also: ErrXXX constants, ModemError, SetParity.
TPortCfg record Comm
Declaration: TPortCfg = record
The complete record contains the following fields:
Initialized Boolean; True if the port is initialized.
Comport Byte value of the COM port being used (1 =
COM1).
PortAddr Word value of the base address of this COM
port.
IntVector Byte value pointing to the interrupt vector
to use.
InBuffer Pointer to the receive buffer.
OutBuffer Pointer to the send buffer.
NewHandler Pointer to the handler used when this COM
port is active.
OldHandler Pointer to the old handler when this COM port
is active.
BuffSize Word value of the size of the input and
output buffers.
InHead Word value pointing to the first character in
the buffer.
InTail Word value pointing to the last character in
the buffer.
InUsed Word value giving the number of characters in
the buffer.
OutHead Word value pointing to the first character to
be sent.
OutTail Word value pointing to the last character to
be sent.
OutUsed Word value giving the number of characters in
the buffer.
HndShkOn Word value signaling when auto handshaking
should start (if enabled).
HndShkOff Word value signaling when auto handshaking
should end (if enabled).
TimeCount Internal counter for user inactivity.
StartCh Character sent to restart incoming characters
(soft handshaking).
StopCh Character sent to stop incoming characters
(soft handshaking).
StatusFlg Byte sized bit flags status variable.
ErrorFlg Byte sized bit flags error variable.
ClearCh Character used to clear the receive buffer.
FIFOs Depth of the FIFO buffers, 0 if disabled.
These variables are handled inside the internal comm
routines, and it is probably a bad idea to change them unless you
really know what you are doing.
See Also:
TRecordCollection object Util
Declaration: TRecordCollection = object(TCollection)
PROCEDURE FreeItem(Item: Pointer); virtual;
end;
The stock TCollection object that comes with the Objects
unit in Turbo Pascal 6.0 or later is meant for use as a
collection of objects. In other words, it calls Dispose with a
destructor which records do not have. TRecordCollection
overrides the FreeItem method to simply call Dispose with no
destructor.
See Also: TCollection.
TStopBits type Comm
Declaration: TStopBits = 1..2;
Defines how many stop bits (either 1 or 2) will be used by
the UART to signal the end of a character. Set this through the
SetStopBits procedure.
See Also: SetStopBits.
TTime record Util
Declaration: TTime = record
Hour, Min, Sec, HSec: Word;
end;
Record used for the TTimer and TCountdownTimer objects.
Holds values for the hour, minute, second and hundredth of a
second.
See Also: TTimer, TCountdownTimer.
TTimer object Util
Declaration: TTimer = object
Start, Stop: TTime;
ElaspedTot : TTime;
Stopped : Boolean;
PROCEDURE ClearTimer;
FUNCTION ElapsedSeconds: Longint;
PROCEDURE ElapsedTime(var Elapse: TTime);
PROCEDURE GetStartTime(var TimeRec: TTime);
PROCEDURE GetStopTime(var TimeRec: TTime);
PROCEDURE ResetTimer;
PROCEDURE StartTimer;
PROCEDURE StopTimer;
end;
This object acts as a kind of stopwatch. You can start and
stop the timer as many times as you wish without losing the "lap
time" being kept internally. If you run the timer for 5 seconds,
stop it for 10, and run it for an additional 5 seconds,
ElapsedSeconds will return a total of 10 seconds of elapsed time.
Note: you must call ClearTimer before you start the timer
for the first time to ensure the proper values are set in the
object. Otherwise you will get wrong results, infinite loops, or
arithmetic overflows (BP7 only). Each method is explained in
more detail below.
ClearTimer Clears the timer and initializes it for use. This
must be called before the timer is started for the
first time. It can also be used during timing to
stop the timer, and clear all internal values to
zero.
ElapsedSeconds Returns the elapsed time in seconds. The timer is
cumulative; if you start the timer and let it run,
stop it, and start it again later, the time will
accumulate instead of start back at zero.
ElapsedTime Returns the elapsed time as a TTime record. This
has the advantage of being a bit more precise than
the ElapsedSeconds method, but requires that you
allocate a TTime variable to hold the results.
GetStartTime Returns the starting time for the timer. This is
the most recent start, not the first one to start
accumulating time.
GetStopTime Returns the most recent stopping time.
ResetTimer Resets the timer to zero without stopping the
timer. Note that is close to, but not quite, the
same as ClearTimer. If the timer is running when
this is called, it will be running when it
returns.
StartTimer Starts the timer by placing the current system
time into the Start record.
StopTimer Stops the timer by placing the current system time
into the Stop record.
See Also: TCountdownTimer, TTime record.
TWordLength type Comm
Declaration: TWordLength = 5..8;
Defines the length of a word (a single character) as far as
the UART is concerned. Typical values for this are either 7 or
8. Most connections to mainframes such as the IBM System/370
will be done using 7-bit word lengths, while most PC-to-PC
connections will be done using 8-bit word lengths.
See Also: SetWordLength.
UART constants Comm
Declaration: (in Const block)
Constants used for referencing the various registers of the
8250B and compatible UARTs.
RBR = 0 Receive buffer register; where incoming characters
are temporarily stored.
THR = 0 Transmit holding register; where outgoing
characters are temporarily stored.
DLL = 0 Divisor latch low; low byte of the desired bps
rate divisor.
IER = 1 Interrupt enable register; bit mask to enable or
disable UART interrupts.
DLM = 1 Divisor latch high; high byte of the desired bps
rate divisor.
IIR = 2 Interrupt ID register; tells you what event
triggered an interrupt.
FCR = 2 FIFO control register; on UARTs with FIFOs,
controls the internal buffers.
LCR = 3 Line control register; controls various aspects of
the data line.
MCR = 4 Modem control register; controls various aspects
of the modem.
LSR = 5 Line status register; gives information on the
ta line.
MSR = 6 Modem status register; gives information on the
modem.
SCR = 7 Scratch register; temporary 8-bit holding area.
See Also: OCW constants.
Upper Util
Declaration: FUNCTION Upper(Strn: String): String;
Converts all lowercase characters in a string to uppercase,
and returns the resulting string.
See Also: Lower.
VSeg Util
Declaration: FUNCTION VSeg: Word;
Returns the segment of video memory for the text screen.
For color displays, this will return the value in SegB000. For
monochrome displays it will return the value in SegB800.
See Also: Color variable.
WaitForRingTrailer Comm
Declaration: PROCEDURE WaitForRingTrailer(PortIdx: Byte);
Waits for the Trailing Edge of Ring Indicator bit to go high
in the modem status register. This signals that the phone has
stopped its current ring.
See Also: LineRinging.
WordLength Comm
Declaration: FUNCTION WordLength(PortIdx: Byte):
WordLength;
Returns the current word length on the COM port. This value
will range from 5 to 8, but will typically be either a 7 or an 8.
See Also: SetWordLength, TWordLength type.
XPos Util
Declaration: FUNCTION XPos(SubStrn, Strn: String); Offset:
Byte): Byte;
Returns the first position at which a substring occurs
within a larger string, or 0 if no offset occurs. The offset
returned is an absolute offset into the string, not a relative
offset based on the value passed in the Offset variable.
See Also: System.Pos.
Appendix A: Glossary
bps: bits per second. This is a measure of how fast data can be
sent over a serial connection. Most non-mainframe connections
are made at 8 bits, 1 stop bit, no parity. There is also what's
known as a start bit, which would then make each character a
total of 10 bits. These connections make it easy to convert bps
directly into cps (characters per second).
batching: Sending more than one file at a time over a protocol
without user intervention between each file. Ymodem is an
example of a batching protocol.
blocking: One method of transferring a file. In a blocking
mode, after each packet of data is sent the sender will wait for
an acknowledgment that the receiver got the data, and it was
uncorrupted. It is slower than streaming since the sender is
inactive until the receiver responds.
checksum: A checksum is a way of checking the integrity of data.
It is computed by taking the sum of all the data and taking the
result modulo 256. The result is always an 8-bit data quantity.
Checksums are not very reliable because it is very feasible for a
data hit to corrupt the data in such a way that the checksum is
still valid. Xmodem is an example of a protocol that uses a
checksum for error correction.
CRC: cyclical redundancy check. A CRC is used to check the
integrity of data. When a CRC is computed for a block of data,
and even one bit in that block changes, the CRC will also change.
CRC is a good way to check for errors when sending data over a
volatile serial connection, such as a phone line. CRC's can be
either 16 or 32 bits in size. Ymodem makes use of a 16-bit CRC.
DCD: Data Carrier Detect. This is one of the lines on your
serial port. When DCD is high, a carrier has been detected.
This really means that you are connected to some kind of remote
system, whether it be modem or another computer through a null
modem connection.
DTR: Data Terminal Ready. One of the lines on your serial port.
DTR must be high to send and receive data on your serial port.
Some new modems see a low DTR line as a command to hang the modem
up, if you were connected.
emulation: A set of codes which define how a remote system
should react to various sequences of characters. Emulation allow
a remote system to do things with the screen that normally would
not be possible using the standard ASCII character set. VT-100
is a popular terminal emulation used by mainframes.
FIFO: First In, First Out. A FIFO, also known as a queue, is
present in the 16550A UART. This buffer allows the serial port
to receive characters quicker than the program can retrieve them,
thus increasing throughput and avoiding overrun errors.
FOSSIL: An acronym for Fido-Opus-Seadog Standard Interface
Layer. A FOSSIL driver provides more complete serial services
that replace the standard BIOS serial drivers. FOSSIL drivers
are used by a lot of bulletin boards and games, as well as the
first version of BBSkit. FOSSIL drivers are limited to only
38,400bps.
host: The end of a user-to-BBS connection that serves the user.
For example, when you call a BBS, the system you are using is the
host. A mainframe is also the host system when you use its
resources.
interrupt-driven: A method of serial communications which allows
the program to do other things while waiting for characters to
arrive at the serial port. When a character does arrive, the
program temporarily suspends what it was doing, grabs the
character, and returns. Interrupt driven routines allow you to
operate at 115,200bps.
modem: A device which allows you to "talk" to other computers
all over the world over a standard phone line. Modem stands for
"modulation/demodulation". A modem is almost always required
equipment for using BBSkit.
polling: A method of serial communications which requires that
the program constantly check, or poll, the serial port for
incoming characters. It is very inefficient.
protocol: A method of sending files over a serial connection is
such a way that the receiver ends up getting an exact duplicate
of the file sent. Most protocols implement some method of error
correction to help cut down on the number of errors that
eventually get through.
streaming: Another method of transferring a file. Streaming
sends each packet of a transfer with little or no waiting between
packets. It is more efficient than blocking since it does not
need to wait on the receiver, but also requires a more advanced
UART at high speeds.
terminal program: A program which allows you to send and receive
characters, and not much else. Most terminal programs include
other bells and whistles, such as transfer protocols. A terminal
program is required for communicating with a host.
UART: Universal Asynchronous Receiver/Transmitter. The chip
that works your serial port, such as the National 16550A.
Xmodem: The original protocol developed strictly for 8-bit data
connections. Xmodem is found in virtually every popular
communications application.
Ymodem: A more advanced version of Xmodem which includes the
ability to send more than one file at a time (known as batching),
more careful error checking, and larger packet sizes.
Zmodem: Another file transfer protocol similar to Ymodem, but it
also has additional features that make it better for file
transfers across packet switching networks that gobble certain
characters. Zmodem also has the ability to resume an aborted
download through the use of Zmodem Crash Recovery. Many popular
terminal programs offer this feature.
Appendix B: Contacting Technical Support
Technical support is available to all registered users free
of charge from the time that registration is received. By "free
of charge" I mean that I will provide as much help as I can in
any way that I can, so long as it does not cost me lots of money.
Support is available over the phone (no collect calls will be
accepted), through United States Mail, through CompuServe,
through the Internet, or through BITNET.
As a college student, my address at school changes with each
year. Not only that, but I sometimes go home for a weekend,
winter break, or spring break. Since this is something that can
be a bother to users, I am taking it upon myself to inform
registered users of my change of address at the beginning of each
school year. The address for that school year and the telephone
number will be provided in a mailing sent to all users through
U.S. Mail. Additional information may be included with this
mailing about technical support.
Stable address/phone number info is:
U.S. Mail (home): BBSkit Technical Support
1888 Edith Marie Drive
Beavercreek, OH 45431-3377
CompuServe: >INTERNET:sjmadsen@miavx1.acs.muohio.edu
Internet: sjmadsen@miavx1.acs.muohio.edu
BITNET: sjmadsen@miavx1
Just about every information service offers some sort of
gateway to the Internet. Please check your information or ask a
system operator on your service about sending and receiving mail
with the Internet. Having access such as this makes it much
easier for you and I to exchange new code, bug fixes, and
information on the development of BBSkit and associated
applications in general.
As an added convenience, I will accept calls for technical
support. As a private developer, there are no hours for
technical support. Instead, I would like to simply ask my users
to call at a reasonable hour. "Reasonable" is anywhere from 8am
to 11pm, but remember that I have a "normal" job, too (at least
during the summer). The best time to reach me would probably be
from 6pm to 11pm, east coast time.
If for some reason I am not home, please leave a message.
To make sure that I receive this message, let whoever answers
know that it is about BBSkit. That way, I'll see it as soon as I
get in. I will return calls for tech support provided that the
calls don't start costing too much. However, the most reliable
method for reaching me for technical support would be through
some means electronic. Sending me mail through CompuServe or
Internet is by far the easiest for both of us. I check my
Internet mail on a daily basis, and you never have to worry about
a busy signal, either. Additionally, my experience has been that
debugging BBSkit applications can be tricky, and the best way for
me to help you with your problem is to actually see the code. It
can get very expensive for both of us to try sending code over
long distance, so including the problematic code in any mail you
send me (US or electronic) is always a great idea!
When calling technical support, please have the following
information available in the event that it is needed to help
diagnose your problem:
* Version of BBSkit being run (use VersionID)
* Version of Turbo Pascal
* Version of DOS
* Computer make & model
* Modem make & model
I will do my best to help you with any problems you may be
having getting BBSkit to work with your hardware. However, I
cannot debug your code for you. Technical support is primarily a
means to getting BBSkit to work with your particular hardware
configuration and making sure that BBSkit is not causing your
problem.
Upgrades to new versions of BBSkit will be very reasonable.
They will include the new printed manual, new disks, and postage.
If there isn't a new manual, the cost will be considerably less,
of course. When an upgrade is ready for release, registered
users will receive postcards informing them of the upgrade and
giving a short list of new features or bug fixes. Typically, my
major upgrade schedule has ended up being on a yearly basis.
Each version of BBSkit usually burns me out for a couple of
months until the following fall, so new upgrades usually appear
sometime in the spring or summer. This isn't set in stone, of
course, it's just supposed to give you a rough idea of when to
expect new & exciting things to play with.
If you would like to get maintenance releases (identified by
a letter following the version, such as 2.0g), these can be
acquired for minimal cost through US Mail or for free if you have
Internet access or are willing to call a host and download a
file. Just call me on my voice line sometime in the evening and
I'll let you know what's going on.
Mailing List
There is now a BBSkit mailing list for those of you with
electronic mail access. This mailing list is currently being run
off of an original NeXT '030 cube running NeXTSTEP 2.0. The list
processor software in use is ListProcessor 6.0b by Anastasios
Kotsikonas. UNIX mailing lists work entirely through email,
provided a kind of conferencing for those unable to access USENET
newsgroups. Additionally, the members of these lists are usually
more interested in the topic at hand, less likely to cause
trouble, and contribute more to the list. I would be very happy
to see you on this list if you have access to Internet mail.
You can subscribe to the list by sending a one-line message
to listproc@nextsrv.cas.muohio.edu of the form:
subscribe bbskit [your name]
Replace [your name] with your real first & last name, as you
would like the other members of the list to see it. Posting a
message to the list is as simple as composing a mail message to
an individual. Simple send the entire message to
bbskit@nextsrv.cas.muohio.edu and the message will be sent to all
of the other members of the list.
ftp site
To make life even more wonderful for those of you with
Internet access, there is also an ftp site which is home to
BBSkit and applications which make use of it. ftp to
ftp.cas.muohio.edu and start looking around in the
/pub/dos/bbskit directory. If you have something of interest,
why not drop it into the incoming/ directory and I can put it up
for everyone else? Examples, neat algorithms that others might
find useful, pretty much anything goes.
Appendix C: Extended Keycodes
AltSpace = $02 CtrlIns = $04 ShiftIns = $05
CtrlDel = $06 ShiftDel = $07 ShiftTab = $0F
AltQ = $10 AltW = $11 AltE = $12
AltR = $13 AltT = $14 AltY = $15
AltU = $16 AltI = $17 AltO = $18
AltP = $19 AltA = $1E AltS = $1F
AltD = $20 AltF = $21 AltG = $22
AltH = $23 AltJ = $24 AltK = $25
AltL = $26 AltZ = $2C AltX = $2D
AltC = $2E AltV = $2F AltB = $30
AltN = $31 AltM = $32 F1 = $3B
F2 = $3C F3 = $3D F4 = $3E
F5 = $3F F6 = $40 F7 = $41
F8 = $42 F9 = $43 F10 = $44
Home = $47 Up = $48 PgUp = $49
Left = $4B Right = $4D End = $4F
Down = $50 PgDn = $51 Ins = $52
Del = $53 ShiftF1 = $54 ShiftF2 = $55
ShiftF3 = $56 ShiftF4 = $57 ShiftF5 = $58
ShiftF6 = $59 ShiftF7 = $5A ShiftF8 = $5B
ShiftF9 = $5C ShiftF10 = $5D CtrlF1 = $5E
CtrlF2 = $5F CtrlF3 = $60 CtrlF4 = $61
CtrlF5 = $62 CtrlF6 = $63 CtrlF7 = $64
CtrlF8 = $65 CtrlF9 = $66 CtrlF10 = $67
AltF1 = $68 AltF2 = $69 AltF3 = $6A
AltF4 = $6B AltF5 = $6C AltF6 = $6D
AltF7 = $6E AltF8 = $6F AltF9 = $70
AltF10 = $71 CtrlPrtSc = $72 CtrlLeft = $73
CtrlRight = $74 CtrlEnd = $75 CtrlPgDn = $76
CtrlHome = $77 Alt1 = $78 Alt2 = $79
Alt3 = $7A Alt4 = $7B Alt5 = $7C
Alt6 = $7D Alt7 = $7E Alt8 = $7F
Alt9 = $80 Alt0 = $81 AltMinus = $82
AltEqual = $83 CtrlPgUp = $84 AltBack = $08